<template>
  <div style="position: relative">
    <div :id="'container' + id" class="point-cloud-container" :style="'height: ' + height + 'vh;'" v-loading="loading">
      <canvas :id="'canvas3d' + id" />
    </div>

    <div class="view-manipulator" id="poly-split-manipulator" tabindex="-1">
      <canvas id="canvasMouse" className="subview-svg"></canvas>
    </div>

    <div class="view-manipulator" id="z-view-manipulator" tabindex="-1">
      <svg class="subview-svg" id="z-view-svg">
        <rect
          x="70"
          y="50"
          width="20"
          height="140"
          fill="#00000000"
          class="line-handle ew-handle"
          id="z-line-left-handle"
        />
        <line x1="80" y1="40" x2="80" y2="200" class="svg-line" id="z-line-left" />

        <rect
          x="90"
          y="30"
          width="40"
          height="20"
          fill="#00000000"
          class="line-handle ns-handle"
          id="z-line-top-handle"
        />
        <line x1="80" y1="40" x2="140" y2="40" class="svg-line" id="z-line-top" />

        <rect
          x="130"
          y="50"
          width="20"
          height="140"
          fill="#00000000"
          class="line-handle ew-handle"
          id="z-line-right-handle"
        />
        <line x1="140" y1="40" x2="140" y2="200" class="svg-line" id="z-line-right" />

        <rect
          x="90"
          y="190"
          width="40"
          height="20"
          fill="#00000000"
          class="line-handle ns-handle"
          id="z-line-bottom-handle"
        />
        <line x1="80" y1="200" x2="140" y2="200" class="svg-line" id="z-line-bottom" />

        <rect
          x="110"
          y="120"
          width="20"
          height="70"
          fill="#00000000"
          class="line-handle ew-handle"
          id="z-line-direction-handle"
        />
        <line x1="110" y1="120" x2="110" y2="40" class="svg-line" id="z-line-direction" />

        <!-- corners -->
        <rect
          x="60"
          y="40"
          width="20"
          height="20"
          fill="#00000000"
          class="line-handle nw-handle"
          id="z-top-left-handle"
        />
        <rect
          x="110"
          y="120"
          width="20"
          height="20"
          fill="#00000000"
          class="line-handle ne-handle"
          id="z-top-right-handle"
        />
        <rect
          x="110"
          y="120"
          width="20"
          height="20"
          fill="#00000000"
          class="line-handle sw-handle"
          id="z-bottom-left-handle"
        />
        <rect
          x="110"
          y="120"
          width="20"
          height="20"
          fill="#00000000"
          class="line-handle se-handle"
          id="z-bottom-right-handle"
        />

        <rect
          x="90"
          y="100"
          width="40"
          height="40"
          fill="#00000000"
          class="line-handle grab-handle"
          id="z-move-handle"
        />
      </svg>
      <div class="v-buttons-wrapper" id="z-v-buttons">
        <!--div id="z-v-auto-rotate" class="ui-button" title="auto-rotate"><span class="ui-icon ui-icon-key"></span></div-->
        <div id="z-v-reset-rotate" class="ui-button" title="z-view-size">
          <!--span class="ui-icon ui-icon-refresh"></span-->
          <span id="z-view-content">宽</span>
        </div>
      </div>
    </div>

    <div class="view-manipulator" id="y-view-manipulator" tabindex="-1">
      <svg class="subview-svg" id="y-view-svg">
        <rect
          x="70"
          y="50"
          width="20"
          height="140"
          fill="#00000000"
          class="line-handle ew-handle"
          id="y-line-left-handle"
        />
        <line x1="80" y1="40" x2="80" y2="200" class="svg-line" id="y-line-left" />

        <rect
          x="90"
          y="30"
          width="40"
          height="20"
          fill="#00000000"
          class="line-handle ns-handle"
          id="y-line-top-handle"
        />
        <line x1="80" y1="40" x2="140" y2="40" class="svg-line" id="y-line-top" />

        <rect
          x="130"
          y="50"
          width="20"
          height="140"
          fill="#00000000"
          class="line-handle ew-handle"
          id="y-line-right-handle"
        />
        <line x1="140" y1="40" x2="140" y2="200" class="svg-line" id="y-line-right" />

        <rect
          x="90"
          y="190"
          width="40"
          height="20"
          fill="#00000000"
          class="line-handle ns-handle"
          id="y-line-bottom-handle"
        />
        <line x1="80" y1="200" x2="140" y2="200" class="svg-line" id="y-line-bottom" />

        <rect
          x="110"
          y="120"
          width="20"
          height="70"
          fill="#00000000"
          class="line-handle ew-handle"
          id="y-line-direction-handle"
        />
        <line x1="110" y1="120" x2="110" y2="40" class="svg-line" id="y-line-direction" />

        <!-- corners -->
        <rect
          x="60"
          y="40"
          width="20"
          height="20"
          fill="#00000000"
          class="line-handle nw-handle"
          id="y-top-left-handle"
        />
        <rect
          x="110"
          y="120"
          width="20"
          height="20"
          fill="#00000000"
          class="line-handle ne-handle"
          id="y-top-right-handle"
        />
        <rect
          x="110"
          y="120"
          width="20"
          height="20"
          fill="#00000000"
          class="line-handle sw-handle"
          id="y-bottom-left-handle"
        />
        <rect
          x="110"
          y="120"
          width="20"
          height="20"
          fill="#00000000"
          class="line-handle se-handle"
          id="y-bottom-right-handle"
        />

        <rect
          x="90"
          y="100"
          width="40"
          height="40"
          fill="#00000000"
          class="line-handle grab-handle"
          id="y-move-handle"
        />
      </svg>
      <div class="v-buttons-wrapper" id="y-v-buttons">
        <div id="y-v-reset-rotate" class="ui-button" title="y-view-size">
          <span id="y-view-content"></span>
        </div>
      </div>
    </div>

    <div class="view-manipulator" id="x-view-manipulator" tabindex="-1">
      <svg class="subview-svg" id="x-view-svg">
        <rect
          x="70"
          y="50"
          width="20"
          height="140"
          fill="#00000000"
          class="line-handle ew-handle"
          id="x-line-left-handle"
        />
        <line x1="80" y1="40" x2="80" y2="200" class="svg-line" id="x-line-left" />

        <rect
          x="90"
          y="30"
          width="40"
          height="20"
          fill="#00000000"
          class="line-handle ns-handle"
          id="x-line-top-handle"
        />
        <line x1="80" y1="40" x2="140" y2="40" class="svg-line" id="x-line-top" />

        <rect
          x="130"
          y="50"
          width="20"
          height="140"
          fill="#00000000"
          class="line-handle ew-handle"
          id="x-line-right-handle"
        />
        <line x1="140" y1="40" x2="140" y2="200" class="svg-line" id="x-line-right" />

        <rect
          x="90"
          y="190"
          width="40"
          height="20"
          fill="#00000000"
          class="line-handle ns-handle"
          id="x-line-bottom-handle"
        />
        <line x1="80" y1="200" x2="140" y2="200" class="svg-line" id="x-line-bottom" />

        <rect
          x="110"
          y="120"
          width="20"
          height="70"
          fill="#00000000"
          class="line-handle ew-handle"
          id="x-line-direction-handle"
        />
        <line x1="110" y1="120" x2="110" y2="40" class="svg-line" id="x-line-direction" />

        <!-- corners -->
        <rect
          x="60"
          y="40"
          width="20"
          height="20"
          fill="#00000000"
          class="line-handle nw-handle"
          id="x-top-left-handle"
        />
        <rect
          x="110"
          y="120"
          width="20"
          height="20"
          fill="#00000000"
          class="line-handle ne-handle"
          id="x-top-right-handle"
        />
        <rect
          x="110"
          y="120"
          width="20"
          height="20"
          fill="#00000000"
          class="line-handle sw-handle"
          id="x-bottom-left-handle"
        />
        <rect
          x="110"
          y="120"
          width="20"
          height="20"
          fill="#00000000"
          class="line-handle se-handle"
          id="x-bottom-right-handle"
        />

        <rect
          x="90"
          y="100"
          width="40"
          height="40"
          fill="#00000000"
          class="line-handle grab-handle"
          id="x-move-handle"
        />
      </svg>
      <div class="v-buttons-wrapper" id="x-v-buttons">
        <div id="x-v-reset-rotate" class="ui-button" title="x-view-size">
          <span id="x-view-content"></span>
        </div>
      </div>
    </div>

    <div class="right-panel-tools" style="position: absolute; right: 0; top: 0; z-index: 2000">
      <el-select size="small" v-model="renderTypeSelection" @change="renderTypeSelectChanged">
        <el-option value="simple" label="默认" />
        <el-option value="gorgeous" label="彩色" />
        <el-option value="deviceId" label="按雷达编号" />
        <el-option value="label" label="按标签" />
        <el-option value="intensity" label="按反射强度（黑白）" />
        <el-option value="intensityGorgeous" label="按反射强度（彩色）" />
      </el-select>
      <el-tooltip effect="light" content="查看" placement="bottom">
        <el-button circle size="mini" icon="el-icon-search" @click="changeLabelTool('view')" style="margin-left: 0" />
      </el-tooltip>
      <el-tooltip effect="light" content="保存" placement="bottom">
        <el-button
          circle
          size="mini"
          icon="fa fa-floppy-o"
          :disabled="tmpSplitPoints.length == 0 && tmpMinusSplitPoints.length == 0"
          @click="addSplitMarkAnnotation(tmpSplitPoints, tmpMinusSplitPoints, 'split', addSplitCallback)"
          style="margin-left: 0"
        />
      </el-tooltip>
      <!--el-tooltip v-if="checkrole(['admin', 'checker', 'marker'])" effect="light" content="画框" placement="bottom">
        <el-button circle size="mini" icon="fa fa-cube" @click="changeLabelTool('cube')" style="margin-left: 0" />
      </el-tooltip-->
      <el-tooltip effect="light" content="画线" placement="bottom">
        <el-button
          v-show="labelTools['pointLine']"
          circle
          size="mini"
          icon="fa fa-circle"
          @click="changeLabelTool('pointLine')"
          style="margin-left: 0"
        />
      </el-tooltip>
      <el-tooltip effect="light" content="多边形选点" placement="bottom">
        <el-button
          v-show="labelTools['polySplit']"
          circle
          size="mini"
          icon="fa fa-lemon-o"
          @click="changeLabelTool('polySplit')"
          style="margin-left: 0"
        />
      </el-tooltip>
      <el-tooltip effect="light" content="矩形框选点" placement="bottom">
        <el-button
          v-show="labelTools['rectSplit']"
          circle
          size="mini"
          icon="fa fa-plus-square-o"
          @click="changeLabelTool('point')"
          style="margin-left: 0"
        />
      </el-tooltip>
      <!--el-tooltip effect="light" content="删点" placement="bottom">
        <el-button
          v-show="labelTools['pointSplit']"
          circle
          size="mini"
          icon="el-icon-remove-outline"
          @click="changeLabelTool('minus')"
          style="margin-left: 0"
        />
      </el-tooltip-->
      <el-tooltip effect="light" content="查看" placement="bottom">
        <el-button circle size="mini" icon="el-icon-view" @click="viewsInitialize()" style="margin-left: 0" />
      </el-tooltip>
    </div>
  </div>
</template>
<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { PCDLoader } from './PCDLoader.js'
import { ResourceTracker } from './ResourceTracker.js'
import { pointsCloudDetails, pcdBlob, pcdBlobWithFlag } from '@/api/mark/onlineCheck'
import { checkRole } from '@/utils/permission'
import { colorRender } from './PCDColorRender.js'
import PlaneView from '../PlaneView'
import { listRemarkBall } from '@/api/mark/remarkBall'
import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js'
import { SelectionBox } from './SelectionBox.js'
import { SelectionHelper } from './SelectionHelper.js'
import { ConvexGeometry } from 'three/examples/jsm/geometries/ConvexGeometry.js'
import Cookies from 'js-cookie'
import tools from './tools/index'
import { addPointsLineInstance } from './utils/AnnotationsLoader'
import { views, SideViews } from './utils/views'
import { xyz_to_psr, euler_angle_to_rotate_matrix, matmul2 } from './utils/data'
import 'jquery-ui-dist/jquery-ui'
import 'jquery-ui-dist/jquery-ui.css'
import { CubeHelper } from './CubeHelper.js'
import { addAnnotation, editAnnotation, deleteAnnotation } from '@/api/mark/markAnnotation'
import { box_to_2d_points } from './tools/cubeToImage'

export default {
  name: 'PointCloud',
  props: {
    height: Number,
    id: String,
    taskId: [String, Number],
    HideTip: Function,
    ShowTip: Function,
    renderType: String,
    cameraPosition: {},
    highLightCubePoints: [String, Boolean],
    attributeNames: {},
    colorNames: {},
    isLoading: Function,
    loading: Boolean,
    sync_highlight_objects: Function,
    sync_clear_highlight_objects: Function,
    changePage: Function,
    setPosition: Function,
    elementsRemark: {},
    handleElementComments: Function,
    changeCubeInfo: Function,
    addSplitMarkAnnotation: Function,
    addMarkAnnotation: Function,
    imageProjection: Function,
  },
  components: {
    PlaneView,
  },
  computed: {
    markAnnotations() {
      return this.$store.state.markData.markAnnotations
    },
    remarkList() {
      return this.$store.state.markData.remarkList
    },
  },
  data() {
    return {
      mQaResultId: [String, Number],
      planeViewDrawer: false,
      animationFrameId: undefined,
      mouseDown: false,
      renderRequested: false,
      pointTextFontSize: 48,
      isFullscreen: false,
      selectedObject: {
        mMarkAnnotationId: null,
        name: '',
        a1: '',
        a2: '',
        a3: '',
        a4: '',
        a5: '',
        a6: '',
        a7: '',
        a8: '',
        remark: '',
        attributes: [],
        type: '',
        imageIndex: '',
        errorType: '',
        mPoint: {
          x: -1,
          y: -1,
          z: -1,
        },
        elementInstance: null,
        position: null,
      },
      toolTopbody: '',
      ctx: null,
      container: null,
      camera: null,
      scene: null,
      highlight_points: null,
      controls: null,
      renderer: null,
      points: null,
      dopplerLines: null,
      keyPoints: [],
      cubeList: new Array(),
      splitPoints: new Array(),
      cubeInstances: new Array(),
      cubeMap: new Map(),
      remarkLabelList: new Array(),
      lineList: new Array(),
      raycaster: null,
      mouse: null,
      pointsCloudData: null,
      annotation: null,
      annotationMap: new Map(),
      currentIndex: -1,
      fileList: {},
      remark: null,
      elements_3D: [],
      INTERSECTED: null,
      selectPointObject: null,
      labelRenderer: null,
      showLabel: true,
      resTracker: null,
      track: null,
      loader: new PCDLoader(),
      pointsFocus: null,
      // 毫米波雷达界面显示激光雷达
      pointsLidar: null,
      selectionBox: null,
      helper: null,
      splitObjects: new Map(),
      tmpSplitPoints: [],
      tmpMinusSplitPoints: [],
      tmpLinePoints: [],
      tmpMinusLinePoints: [],
      splitRange: null,
      renderTypeSelection: null,
      labelTool: null,
      labelTools: {
        polySplit: false,
        rectSplit: false,
        pointLine: false,
      },
      linePoints: [],
      sphereInter: null,
      currentLine: null,
      remarkBallPoint: null,
      showViews: false,
      sideViews: null,
      projectedCube: null,
      autoSaveParams: {
        add: false,
        edit: false,
      },
    }
  },
  methods: {
    // 初始化3D视窗相关对象
    init() {
      if (this.selectDictLabel(this.attributeNames, 'labelTools')) {
        let labelTools = JSON.parse(this.selectDictLabel(this.attributeNames, 'labelTools'))
        labelTools.forEach((element) => {
          this.labelTools[element] = true
        })
      }
      this.renderTypeSelection = this.renderType
      this.resTracker = new ResourceTracker()
      this.track = this.resTracker.track.bind(this.resTracker)
      this.container = document.getElementById('container' + this.id)
      let canvas3d = document.getElementById('canvas3d' + this.id)
      this.raycaster = new THREE.Raycaster()
      this.mouse = new THREE.Vector2()
      this.scene = new THREE.Scene()
      this.camera = new THREE.PerspectiveCamera(
        10,
        this.container.offsetWidth / this.container.offsetHeight,
        0.1,
        10000
      )

      for (let ii = 0; ii < views.length; ++ii) {
        const view = views[ii]
        const asp = this.container.offsetWidth / this.container.offsetHeight

        const camera = new THREE.OrthographicCamera(-3 * asp, 3 * asp, 3, -3, -3, 3)
        view.camera = camera
      }

      try {
        let tmpPosition = JSON.parse(this.cameraPosition)
        this.camera.position.x = tmpPosition.x
        this.camera.position.y = tmpPosition.y
        this.camera.position.z = tmpPosition.z
      } catch {
        this.camera.position.x = 0
        this.camera.position.y = 400
        this.camera.position.z = 300
      }
      this.camera.up.set(0, 0, 1)
      this.camera.lookAt(new THREE.Vector3(0, 0, 0))
      this.scene.add(this.camera)

      this.scene = new THREE.Scene()

      let showGridHelper = this.selectDictLabel(this.attributeNames, 'gridHelper')
      if (showGridHelper) {
        try {
          let gridHelper = new THREE.GridHelper(parseFloat(showGridHelper), parseFloat(showGridHelper))
          gridHelper.rotation.x = Math.PI / 2
          this.scene.add(gridHelper)
        } catch {}
      }

      // 添加坐标轴
      let axesHelper = new THREE.AxesHelper(5)
      this.scene.add(axesHelper)

      this.renderer = new THREE.WebGLRenderer({
        antialias: true,
        canvas: canvas3d,
        powerPreference: 'high-performance',
        preserveDrawingBuffer: true,
      })
      this.renderer.setPixelRatio(window.devicePixelRatio)
      this.renderer.setSize(this.container.offsetWidth, this.container.offsetHeight)
      this.renderer.setClearColor(0x000000, 0.0)

      const renderDom = this.renderer.domElement
      this.container.appendChild(renderDom)

      this.labelRenderer = new CSS2DRenderer()
      this.labelRenderer.setSize(this.container.offsetWidth, this.container.offsetHeight)
      this.labelRenderer.domElement.style.position = 'absolute'
      this.labelRenderer.domElement.style.top = '0px'
      this.labelRenderer.domElement.style.pointerEvents = 'none'
      this.container.appendChild(this.labelRenderer.domElement)

      this.controls = new OrbitControls(this.camera, renderDom)
      this.controls.zoomSpeed = 3
      this.controls.panSpeed = 1
      this.controls.keyPanSpeed = 9.0
      this.controls.rotateSpeed = 1
      this.controls.maxPolarAngle = Math.PI * 0.5
      this.controls.enableKeys = false
      // this.controls.enableDamping = true
      // this.controls.dampingFactor = 0.98
      this.controls.addEventListener('change', this.requestRenderIfNotRequested)

      renderDom.addEventListener('mousemove', this.onMouseMove, false)
      renderDom.addEventListener('mousedown', this.onMouseDown, false)
      renderDom.addEventListener('mouseup', this.onMouseUp, false)
      renderDom.addEventListener('wheel', this.onMouseWheel, false)

      window.addEventListener('keypress', this.onKeyPress)
      this.selectionBox = new SelectionBox(this.camera, this.scene)
      this.selectionBox.labelTool = 'view'
      this.helper = new SelectionHelper(this.selectionBox, this.renderer, 'selectBox')

      // 验收球点云选择工具
      const remarkGeometry = this.track(new THREE.BufferGeometry())
      const canvasP = document.createElement('canvas')
      canvasP.width = 100
      canvasP.height = 100
      const contextP = canvasP.getContext('2d')
      contextP.fillStyle = '#ff0000'
      contextP.arc(50, 50, 45, 0, 2 * Math.PI)
      contextP.fill()
      const textureP = this.track(new THREE.Texture(canvasP))
      textureP.needsUpdate = true
      const remarkMaterial = this.track(
        new THREE.PointsMaterial({ size: 12, vertexColors: THREE.VertexColors, depthTest: false, map: textureP })
      )
      remarkMaterial.sizeAttenuation = false
      remarkGeometry.setAttribute('position', new THREE.Float32BufferAttribute([0, 0, 0], 3))
      remarkGeometry.setAttribute('color', new THREE.Float32BufferAttribute([1, 0, 0], 3))

      this.remarkBallPoint = this.track(new THREE.Points(remarkGeometry, remarkMaterial))
      this.remarkBallPoint.visible = false
      this.remarkBallPoint.name = 'remarkBallPoint'
      this.scene.add(this.remarkBallPoint)

      this.render()

      const mouseEventHandlers = {
        divOnWhell: this.on_wheel,
      }

      this.sideViews = new SideViews(mouseEventHandlers)
      this.sideViews.renderer = this.renderer
      this.sideViews.init()

      this.selectionBox = new SelectionBox(this.camera, this.scene)
      this.selectionBox.labelTool = 'view'
      this.helper = new SelectionHelper(this.selectionBox, this.renderer, 'selectBox')

      renderDom.addEventListener('pointerdown', (event) => {
        if (!this.renderer) return

        if (event.shiftKey && this.selectionBox.labelTool !== 'view') {
          this.helper.enabled = true
          this.controls.enabled = false
        } else if (this.startCubeSelection) {
          this.helper.enabled = true
          this.selectionBox.labelTool = 'cube'
          this.controls.enabled = false
        } else {
          return
        }

        const rect = renderDom.getBoundingClientRect()

        this.selectionBox.startPoint.set(
          ((event.clientX - rect.left) / rect.width) * 2 - 1,
          -((event.clientY - rect.top) / rect.height) * 2 + 1,
          0.5
        )
      })

      renderDom.addEventListener('pointerup', (event) => {
        if (!this.renderer) return
        if (this.controls.enabled) return

        // if (event.shiftKey && this.selectionBox.labelTool !== 'view') {
        // this.helper.enabled = false
        this.startCubeSelection = false
        this.controls.enabled = true
        // } else if (this.startCubeSelection) {
        //   this.helper.enabled = false
        //   this.controls.enabled = true
        // } else {
        //   return
        // }

        const rect = renderDom.getBoundingClientRect()

        this.selectionBox.endPoint.set(
          ((event.clientX - rect.left) / rect.width) * 2 - 1,
          -((event.clientY - rect.top) / rect.height) * 2 + 1,
          0.5
        )

        const selected = this.selectionBox.select()
        if (!selected) return
        if (this.selectionBox.labelTool === 'cube') {
          const cubePoints = [],
            pointsArray = []
          cubePoints.push(...selected.pointsIndex)
          cubePoints.forEach((i) => {
            pointsArray.push(
              new THREE.Vector3(
                this.scene.points.geometry.attributes.position.array[3 * i],
                this.scene.points.geometry.attributes.position.array[3 * i + 1],
                this.scene.points.geometry.attributes.position.array[3 * i + 2]
              )
            )
          })
          const box3 = new THREE.Box3()
          box3.setFromPoints(pointsArray)
          const helper = new THREE.Box3Helper(box3, 0xffff00)
          helper.updateMatrixWorld()
          helper.scale.multiplyScalar(2)
          this.addMarkAnnotation(helper, (result) => {
            if (result.ret === 'confirm') {
              const assets = {
                mMarkAnnotationId: null,
                fileName: result.form.fileName,
                mQaResultId: result.form.mQaResultId,
                name: result.form.name,
              }
              for (let ii = 1; ii <= 8; ii++) {
                assets['a' + ii] = result.form['a' + ii]
                assets['b' + ii] = result.form['b' + ii]
              }
              const cubeMesh = this.createCubeMesh(helper, assets)
              this.cubeList.push(cubeMesh)
              this.cubeInstances.push(cubeMesh)
            } else {
              this.scene.remove(cubeMesh)
            }
          })
        } else if (this.selectionBox.labelTool === 'split') {
          this.tmpSplitPoints.push(...selected.pointsIndex)
          this.tmpMinusSplitPoints.push(...selected.minusPointsIndex)
          let tmpPoints = []
          this.tmpSplitPoints.forEach((index) => {
            if (this.tmpMinusSplitPoints.indexOf(index) == -1 && tmpPoints.indexOf(index) == -1) {
              tmpPoints.push(index)
            }
          })
          this.tmpSplitPoints = tmpPoints
          tmpPoints = []
          this.tmpMinusSplitPoints.forEach((index) => {
            if (this.tmpSplitPoints.indexOf(index) == -1 && tmpPoints.indexOf(index) == -1) {
              tmpPoints.push(index)
            }
          })
          this.tmpMinusSplitPoints = tmpPoints

          this.pointsCloudData.needsUpdate = true
        }

        this.requestRenderIfNotRequested()
      })

      const autoSaveThread = setInterval(() => {
        if (this.renderer) {
          this.autoSave()
        } else {
          clearInterval(autoSaveThread)
        }
      }, 360000)
    },
    add_range_box(radius) {
      if (!radius) radius = 60
      var h = 1

      var body = []

      var segments = 64
      for (var i = 0; i < segments; i++) {
        var theta1 = ((2 * Math.PI) / segments) * i
        var x1 = Math.cos(theta1)
        var y1 = Math.sin(theta1)

        var theta2 = ((2 * Math.PI) / segments) * ((i + 1) % segments)
        var x2 = Math.cos(theta2)
        var y2 = Math.sin(theta2)

        body.push(x1, y1, h, x2, y2, h)
      }

      var bbox = new THREE.BufferGeometry()
      bbox.addAttribute('position', new THREE.Float32BufferAttribute(body, 3))

      var box = new THREE.LineSegments(bbox, new THREE.LineBasicMaterial({ color: 0x666666, linewidth: 1 }))

      box.scale.x = radius
      box.scale.y = radius
      box.scale.z = -3
      box.position.x = 0
      box.position.y = 0
      box.position.z = 0
      box.computeLineDistances()

      this.scene.add(box)
    },
    // 获取点云数据
    async getPointsCloud(
      fileList,
      currentIndex,
      mQaResultId,
      playModel = false,
      showAttributesText2D = true,
      pcdFlag = null
    ) {
      if (this.labelTool && this.labelTool.reset) {
        this.labelTool.reset()
      }
      this.isLoading(!playModel)
      this.showLabel = showAttributesText2D
      this.scene.showLabel = showAttributesText2D
      this.fileList = fileList
      this.currentIndex = currentIndex
      this.mQaResultId = mQaResultId
      this.selectedObject = {
        a1: '',
        remark: '',
        attributes: [],
        type: '',
        imageIndex: '',
      }

      for (let key in this.elementsRemark) {
        delete this.elementsRemark[key]
      }
      if (!playModel) {
        const storeKey = 'TaskId:' + this.taskId + ';mQaResultId:' + mQaResultId
        const readValue = this.remarkList.get(storeKey)
        if (readValue) {
          readValue.forEach((ball) => {
            if (ball.trackId) {
              let key = ball.trackId
              if (!key.startsWith('lou-')) {
                key += '-' + ball.mType
              }
              this.elementsRemark[key] = ball.remark
              this.elementsRemark['ball-' + key] = ball
            }
          })
        } else {
          await listRemarkBall({ taskId: this.taskId, mQaResultId: mQaResultId }).then((response) => {
            let remarkBallList = response.rows
            if (remarkBallList) {
              remarkBallList.forEach((ball) => {
                if (ball.trackId) {
                  let key = ball.trackId
                  if (!key.startsWith('lou-')) {
                    key += '-' + ball.mType
                  }
                  this.elementsRemark[key] = ball.remark
                  this.elementsRemark['ball-' + key] = ball
                }
              })
            }
          })
        }
      }

      if (pcdFlag) {
        this.$get(
          pcdFlag + mQaResultId,
          (blobFromIndexedDB) => {
            let blobUrl = URL.createObjectURL(blobFromIndexedDB.blob)
            this.loader.track = this.track
            this.loader.renderType = this.renderTypeSelection
            this.loader.load(blobUrl, (points) => {
              blobUrl = URL.revokeObjectURL(blobUrl)
              this.pointsCloudData = points
              this.annotation = null
              this.threejsRender(playModel)
            })
            blobFromIndexedDB = null
          },
          () => {
            pcdBlobWithFlag(mQaResultId, pcdFlag).then((response) => {
              let blob = new Blob([response.data], { type: 'application/octet-stream' })
              let blobUrl = URL.createObjectURL(blob)
              this.loader.track = this.track
              this.loader.renderType = this.renderTypeSelection
              this.loader.load(blobUrl, (points) => {
                blobUrl = URL.revokeObjectURL(blobUrl)
                this.pointsCloudData = points
                this.annotation = null
                this.threejsRender(playModel)
                let _data = {
                  blob: blob,
                  file_name: pcdFlag + mQaResultId,
                }
                this.$save(_data)
                _data = null
                blob = null
              })
            })
          }
        )
      } else {
        const readValue = this.markAnnotations.get('MA:' + mQaResultId)
        if (readValue) {
          this.$get(
            mQaResultId,
            (blobFromIndexedDB) => {
              let blobUrl = URL.createObjectURL(blobFromIndexedDB.blob)
              this.loader.track = this.track
              this.loader.renderType = this.renderTypeSelection
              this.loader.load(blobUrl, (points) => {
                blobUrl = URL.revokeObjectURL(blobUrl)
                this.pointsCloudData = points
                this.annotation = readValue
                this.threejsRender(playModel)
              })
              blobFromIndexedDB = null
            },
            () => {
              pcdBlob(mQaResultId).then((response) => {
                let blob = new Blob([response.data], { type: 'application/octet-stream' })
                let blobUrl = URL.createObjectURL(blob)
                this.loader.track = this.track
                this.loader.renderType = this.renderTypeSelection
                this.loader.load(blobUrl, (points) => {
                  blobUrl = URL.revokeObjectURL(blobUrl)
                  this.pointsCloudData = points
                  this.annotation = readValue
                  this.threejsRender(playModel)
                  let _data = {
                    blob: blob,
                    file_name: mQaResultId,
                  }
                  this.$save(_data)
                  _data = null
                  blob = null
                })
              })
            }
          )
        } else {
          console.debug('cache not found:', mQaResultId)
          pointsCloudDetails(mQaResultId).then((res) => {
            if (res.fileType === 'pcd') {
              this.markAnnotations.set('MA:' + mQaResultId + '', res.annotation)
              this.$get(
                mQaResultId,
                (blobFromIndexedDB) => {
                  let blobUrl = URL.createObjectURL(blobFromIndexedDB.blob)
                  this.loader.track = this.track
                  this.loader.renderType = this.renderTypeSelection
                  this.loader.load(blobUrl, (points) => {
                    blobUrl = URL.revokeObjectURL(blobUrl)
                    this.pointsCloudData = points
                    this.annotation = res.annotation
                    this.threejsRender(playModel)
                  })
                },
                () => {
                  pcdBlob(mQaResultId).then((response) => {
                    let blob = new Blob([response.data], { type: 'application/octet-stream' })
                    let blobUrl = URL.createObjectURL(blob)
                    this.loader = new PCDLoader()
                    this.loader.track = this.track
                    this.loader.renderType = this.renderTypeSelection
                    this.loader.load(blobUrl, (points) => {
                      blobUrl = URL.revokeObjectURL(blobUrl)
                      this.pointsCloudData = points
                      this.annotation = res.annotation
                      this.threejsRender(playModel)
                      let _data = {
                        blob: blob,
                        file_name: mQaResultId,
                      }
                      this.$save(_data)
                      _data = null
                      blob = null
                    })
                  })
                }
              )
            } else if (res.fileType === 'jbin') {
              this.pointsCloudData = this.loadJsonPCD(res.pointsCloud)
              this.annotation = res.annotation
              this.threejsRender(playModel)
            }
          })
        }

        let radarView = this.selectDictLabel(this.attributeNames, 'radarView')
        if (radarView == 'true') {
          pcdBlobWithFlag(mQaResultId, 'Bumper').then((response) => {
            const blob = new Blob([response.data], { type: 'application/octet-stream' })
            let blobUrl = URL.createObjectURL(blob)
            this.loader.track = this.track
            this.loader.renderType = 'benzLabel'
            this.loader.load(blobUrl, (points) => {
              blobUrl = URL.revokeObjectURL(blobUrl)
              if (this.pointsLidar) {
                this.scene.remove(this.pointsLidar)
                this.pointsLidar.geometry.dispose()
                this.pointsLidar.material.dispose()
              }
              this.pointsLidar = points.children[points.children.length - 1]
              this.pointsLidar.isBackground = true
              this.pointsLidar.material.size = 1
              this.scene.add(this.pointsLidar)
              // this.renderer.render(this.scene, this.camera)
              // this.labelRenderer.render(this.scene, this.camera)
              this.render()
            })
          })
        }
      }
    },
    threejsRender(playModel) {
      this.addPoints()
      this.isLoading(false)
      // this.render()
      this.asyncAddCube(playModel).then(
        () => {
          this.render()
          this.$store.state.markData.playStatus.pcd = true
        },
        (message) => {
          console.log(message)
        }
      )
      this.setPosition(this.selectedObjectA1, null, '', null, null, null, null, null)
    },
    // 异步渲染矩形图形
    asyncAddCube(playModel) {
      let promise1 = new Promise((resolve, reject) => {
        this.addCube(playModel)
        resolve('cube loaded.')
      })
      return promise1
    },
    // 获取a1对象的属性值
    getSelectedObjectAttributes(a1) {
      for (let i = 0; i < this.cubeList.length; i++) {
        if (this.cubeList[i].tag) {
          const _array = this.cubeList[i].tag.split(';')
          if (a1 == _array[1]) {
            const attributes = []
            for (let i = 1; i <= 9; i++) {
              if (_array[i] && _array[i] != null && _array[i] != '' && _array[i] != 'null') {
                try {
                  let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'a' + i + '_3d'))
                  let _values = jsonObject.values[_array[i]]
                  if (_values == null || _values == undefined || _values == '') _values = _array[i]
                  let key = jsonObject.typeDesc
                  let value = _values
                  let _data = {
                    key,
                    value,
                  }
                  attributes.push(_data)
                } catch {}
              }
            }
            return attributes
          }
        }
      }
      return []
    },
    clear_highlight_objects() {
      if (this.highlight_points) {
        this.scene.remove(this.highlight_points)
      }
    },
    // 定位缩放视图到选中矩形，并高亮矩形
    highlight_objects(eventSource, selectedObject, isZoom = true, hideOther = false) {
      this.selectedObject = selectedObject
      let found = false
      let tmpCube = selectedObject.cubeMesh

      for (let i = 0; i < this.cubeList.length; i++) {
        if (this.cubeList[i].tag) {
          if (this.selectedObject.a1 == this.cubeList[i].tag.split(';')[1]) {
            tmpCube = this.cubeList[i]
            tmpCube.visible = true
            this.focusInSideViews(tmpCube)
            found = true
          } else {
            this.cubeList[i].visible = !hideOther
            this.cubeList[i].arrow.visible = !hideOther
            this.cubeList[i].directLine.visible = !hideOther
            this.cubeList[i].label.visible = !hideOther
          }
        }
      }

      if (hideOther) {
        this.splitObjects.forEach((element) => {
          this.hideSplitInstance(element, false)
        })
        this.splitPoints.forEach((pointsMesh) => {
          pointsMesh.visible = false
        })
        if (this.scene.pointsLines) {
          this.scene.pointsLines.forEach((pointsLine) => {
            pointsLine.visible = false
            pointsLine.line.visible = false
            pointsLine.label.visible = false
          })
        }
        if (this.lineList) {
          this.lineList.forEach((remark) => {
            remark.visible = false
          })
        }
      } else {
        this.splitObjects.forEach((element) => {
          this.addSplitInstance(element, false)
        })
        this.splitPoints.forEach((pointsMesh) => {
          pointsMesh.visible = true
        })
        if (this.scene.pointsLines) {
          this.scene.pointsLines.forEach((pointsLine) => {
            pointsLine.visible = true
            pointsLine.line.visible = true
            pointsLine.label.visible = this.scene.showLabel
          })
        }
        if (this.lineList) {
          this.lineList.forEach((remark) => {
            remark.visible = true
          })
        }
      }

      if (tmpCube) this.drawEightPoints(tmpCube.eightPoints)

      if (found) {
        if (tmpCube && this.selectedObject.type == '3d') {
          // 更新验收标识
          if (this.elementsRemark[this.selectedObject.a1 + '-3d']) {
            this.scene.add(tmpCube.remarkLabel)
            this.remarkLabelList.push(tmpCube.remarkLabel)
          } else {
            this.scene.remove(tmpCube.remarkLabel)
            for (let i = 0; i < this.remarkLabelList.length; i++) {
              if (this.remarkLabelList[i].tag && this.remarkLabelList[i].tag == tmpCube.remarkLabel.tag) {
                this.remarkLabelList.splice(i, 1)
                break
              }
            }
          }
        }

        if (isZoom) {
          // 点击3d矩形高亮并缩放三维视角旋转问题，之所以会旋转是因为在缩放摄像机时，从摄像机当前坐标
          // 调整了lookAt到新坐标再拉近距离，在三维透视里就会有角度变化。处理办法就是不改变新lookAt对应的摄像机的角度，然后再拉近
          let cubeCenterPoint = this.calcCubeCenterPoint(tmpCube.eightPoints)
          // 查找矩形的中心位置，计算长宽高的中点，用长宽高的一半加上x,y,z轴最小值
          let x = cubeCenterPoint.x
          let y = cubeCenterPoint.y
          let z = cubeCenterPoint.z
          if (
            this.selectedObject.mPoint.x != -1 &&
            this.selectedObject.mPoint.y != -1 &&
            this.selectedObject.mPoint.z != -1
          ) {
            x = this.selectedObject.mPoint.x
            y = this.selectedObject.mPoint.y
            z = this.selectedObject.mPoint.z
          }
          //distance为距离系数，值越小距离越近，下面是计算矩形中心点到摄像机的三维空间内直线长度距离，设为1时摄像机的x,y与矩形第一个点的x,y接近，z相差摄像机的俯视高度差，
          const distance = 10 * Math.max(cubeCenterPoint.maxL, cubeCenterPoint.maxW, cubeCenterPoint.maxH)
          let selectCenterPoint = this.calcCameraOffsetPosition(cubeCenterPoint, distance)
          this.controls.target.copy({ x, y, z })
          this.camera.position.set(selectCenterPoint.x1, selectCenterPoint.y1, selectCenterPoint.z1)
          this.camera.lookAt(x, y, z)
          this.camera.updateMatrix()
          this.controls.update()
        }
      }

      this.render()
    },
    drawEightPoints(eightPoints) {
      let geometry_highlight = this.track(new THREE.BufferGeometry())
      let canvas_temp0 = document.createElement('canvas')
      canvas_temp0.width = 100
      canvas_temp0.height = 100
      let context0 = canvas_temp0.getContext('2d')
      context0.fillStyle = '#ffffff'
      context0.arc(50, 50, 45, 0, 2 * Math.PI)
      context0.fill()
      let texture0 = this.track(new THREE.Texture(canvas_temp0))
      texture0.needsUpdate = true
      let material_hightlight = this.track(
        new THREE.PointsMaterial({ size: 6, color: 0x0080ff, depthTest: false, map: texture0 })
      )
      material_hightlight.sizeAttenuation = false
      geometry_highlight.setAttribute('position', new THREE.Float32BufferAttribute(eightPoints, 3))

      if (this.highlight_points) {
        this.scene.remove(this.highlight_points)
        if (this.scene.eightPoints && this.scene.eightPoints.length > 0) {
          this.scene.eightPoints.forEach((p) => this.scene.remove(p))
        }
      }

      this.scene.eightPoints = []

      this.highlight_points = this.track(new THREE.Points(geometry_highlight, material_hightlight))
      this.scene.add(this.highlight_points)
    },
    showMarkAnnotations(mMarkAnnotationIds) {
      for (let i = 0; i < this.cubeList.length; i++) {
        if (this.cubeList[i].mMarkAnnotationId) {
          const markAnnotation = this.cubeList[i]
          if (mMarkAnnotationIds.indexOf(markAnnotation.mMarkAnnotationId) != -1) {
            markAnnotation.show()
          } else {
            markAnnotation.hide()
          }
        }
      }

      this.splitObjects.forEach((element, key) => {
        if (mMarkAnnotationIds.indexOf(key) != -1) this.addSplitInstance(element, false)
        else this.hideSplitInstance(element, false)
      })

      this.splitPoints.forEach((pointsMesh) => {
        if (mMarkAnnotationIds.indexOf(pointsMesh.mMarkAnnotationId) != -1) pointsMesh.visible = true
        else pointsMesh.visible = false
      })

      this.render()
    },
    // 矩形定位缩放时，计算摄像机移动后的坐标
    calcCameraOffsetPosition(selectCubeCenterPoint, distance) {
      // x0,y0,z0为摄像机重新定位前的位置
      let x0 = this.camera.position.x
      let y0 = this.camera.position.y
      let z0 = this.camera.position.z
      // 根据新旧目标位移差计算摄像机新坐标
      x0 = selectCubeCenterPoint.x - this.controls.target.x + x0
      y0 = selectCubeCenterPoint.y - this.controls.target.y + y0
      z0 = selectCubeCenterPoint.z - this.controls.target.z + z0
      let x = selectCubeCenterPoint.x
      let y = selectCubeCenterPoint.y
      let z = selectCubeCenterPoint.z
      // 计算拉近摄像机后摄像机坐标
      let x1 = (distance * (x0 - x)) / Math.sqrt((x0 - x) * (x0 - x) + (y0 - y) * (y0 - y) + (z0 - z) * (z0 - z)) + x
      let y1 = (distance * (y0 - y)) / Math.sqrt((x0 - x) * (x0 - x) + (y0 - y) * (y0 - y) + (z0 - z) * (z0 - z)) + y
      let z1 = (distance * (z0 - z)) / Math.sqrt((x0 - x) * (x0 - x) + (y0 - y) * (y0 - y) + (z0 - z) * (z0 - z)) + z
      return { x1: x1, y1: y1, z1: z1 }
    },
    // 计算矩形的中心点坐标
    calcCubeCenterPoint(eight_points) {
      // 找出矩形最长边长度值，乘以distance系数，让矩形最大边可以完整显示在摄像机内
      let maxL = 0,
        maxW = 0,
        maxH = 0
      for (let i = 3; i < 24; i += 3) {
        maxL = Math.max(Math.abs(eight_points[i] - eight_points[i - 3]), maxL)
        maxW = Math.max(Math.abs(eight_points[i + 1] - eight_points[i + 1 - 3]), maxW)
        maxH = Math.max(Math.abs(eight_points[i + 2] - eight_points[i + 2 - 3]), maxH)
      }
      // 查找矩形的中心位置，计算长宽高的中点，用长宽高的一半加上x,y,z轴最小值
      let x = Math.min(eight_points[0], eight_points[6]) + maxL / 2
      let y = Math.min(eight_points[1], eight_points[7]) + maxW / 2
      let z = Math.min(eight_points[2], eight_points[23]) + maxH / 2
      return {
        x: x,
        y: y,
        z: z,
        maxL: maxL,
        maxW: maxW,
        maxH: maxH,
      }
    },
    // 添加点云数据到3D视窗
    addPoints() {
      this.autoSave()
      if (this.scene.eightPoints && this.scene.eightPoints.length > 0) {
        this.scene.eightPoints.forEach((p) => this.scene.remove(p))
      }
      if (this.splitRange) {
        if (this.splitRange.pointsMesh) this.scene.remove(this.splitRange.pointsMesh)
        this.scene.remove(this.splitRange)
      }
      this.splitPoints.forEach((pointsMesh) => {
        this.scene.remove(pointsMesh)
      })
      if (this.scene.pointsLines) {
        this.scene.pointsLines.forEach((pointsLine) => {
          this.scene.remove(pointsLine.line)
          this.scene.remove(pointsLine)
        })
      }
      for (let i = 0; i < this.cubeList.length; i++) {
        if (this.cubeList[i].boxHelper) {
          this.scene.remove(this.cubeList[i].boxHelper)
        }
        this.scene.remove(this.cubeList[i])
      }
      for (let i = 0; i < this.lineList.length; i++) {
        this.scene.remove(this.lineList[i])
      }
      if (this.scene.lineList) {
        for (let i = 0; i < this.scene.lineList.length; i++) {
          this.scene.remove(this.scene.lineList[i])
        }
      }
      for (let i = 0; i < this.remarkLabelList.length; i++) {
        this.scene.remove(this.remarkLabelList[i])
      }
      if (this.scene.points) {
        try {
          this.scene.remove(this.scene.points)
        } catch (e) {
          console.log(e)
        }
      }
      if (this.pointsFocus) {
        this.scene.remove(this.pointsFocus)
        this.pointsFocus.geometry.dispose()
        this.pointsFocus.material.dispose()
      }
      if (this.keyPoints.length > 0) {
        for (let i = 0; i < this.keyPoints.length; i++) {
          this.keyPoints[i].geometry.dispose()
          this.keyPoints[i].material.dispose()
          this.scene.remove(this.keyPoints[i])
        }
      }
      if (this.highlight_points) {
        this.scene.remove(this.highlight_points)
      }
      if (this.selectPointObject) {
        this.scene.remove(this.selectPointObject)
      }
      if (this.dopplerLines) {
        this.scene.remove(this.dopplerLines)
      }
      this.resTracker.dispose()

      if (this.pointsCloudData) {
        if (this.pointsCloudData.children.length > 1) {
          this.dopplerLines = this.pointsCloudData.children[0]
          this.scene.add(this.dopplerLines)
        }
        this.scene.points = this.pointsCloudData.children[this.pointsCloudData.children.length - 1]
        this.scene.add(this.scene.points)
      }

      this.cubeList = new Array()
      this.cubeInstances = new Array()
      this.lineList = new Array()
      this.splitPoints = new Array()
      this.splitObjects = new Map()
    },
    addSplitInstance(annotationObject, playModel) {
      let pointsIndex = annotationObject.threeD.bndbox.x.split(',')
      let fillStyle_r = this.selectDictLabel(this.colorNames, annotationObject.name)
      if (!fillStyle_r) {
        fillStyle_r = 'rgb(255,255,0)'
      }
      let fillStyle = fillStyle_r.replace('rgb(', '').replace(')', '').replace(' ', '')
      fillStyle = fillStyle.split(',')
      let splitViewMode = this.selectDictLabel(this.attributeNames, 'splitViewMode')
      if (splitViewMode && splitViewMode == 'highLight') {
        const position = []
        const colors = []
        const positionArray = this.scene.points.geometry.attributes.position.array
        pointsIndex.forEach((index) => {
          position.push(positionArray[3 * index], positionArray[3 * index + 1], positionArray[3 * index + 2])
          colors.push(parseInt(fillStyle[0]) / 255.0, parseInt(fillStyle[1]) / 255.0, parseInt(fillStyle[2]) / 255.0)
        })
        const geometry = this.track(new THREE.BufferGeometry())
        if (position.length > 0) geometry.setAttribute('position', new THREE.Float32BufferAttribute(position, 3))
        if (colors.length > 0) geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3))
        geometry.computeBoundingSphere()
        let pointSize = parseFloat(Cookies.get('pointSize'))
        if (!pointSize) pointSize = 2
        let material = this.track(new THREE.PointsMaterial({ size: pointSize * 2 }))
        material.color.setHex(0xffffff)
        material.sizeAttenuation = false
        material.vertexColors = true
        material.depthTest = false
        material.fog = false
        const pointsMesh = this.track(new THREE.Points(geometry, material))
        this.scene.add(pointsMesh)
        pointsMesh.mMarkAnnotationId = annotationObject.mMarkAnnotationId
        pointsMesh.annotationObject = annotationObject
        pointsMesh.annotationObject.x = annotationObject.threeD.bndbox.x
        pointsMesh.annotationObject.y = annotationObject.threeD.bndbox.y
        pointsMesh.annotationObject.z = annotationObject.threeD.bndbox.z
        let description = annotationObject.name + ':3;'
        let attrs = annotationObject.threeD.other_attributes
        for (let i = 1; i <= 9; i++) {
          if (attrs['a' + i]) {
            description += attrs['a' + i] + ';'
          }
        }
        pointsMesh.tag = description
        this.splitPoints.push(pointsMesh)
      }

      pointsIndex.forEach((index) => {
        let intensity = 1 //this.scene.points.geometry.attributes.intensities.array[index];
        this.scene.points.geometry.attributes.color.array[3 * index] = (intensity * parseInt(fillStyle[0])) / 255.0
        this.scene.points.geometry.attributes.color.array[3 * index + 1] = (intensity * parseInt(fillStyle[1])) / 255.0
        this.scene.points.geometry.attributes.color.array[3 * index + 2] = (intensity * parseInt(fillStyle[2])) / 255.0
      })

      if (!annotationObject.label) {
        let labelContent = ''
        let _values = undefined
        if (this.selectDictLabel(this.attributeNames, 'labelName')) {
          try {
            let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'labelName'))
            _values = jsonObject.values[annotationObject.name]
          } catch (e) {
            console.log(e)
          }
        }
        labelContent += _values === undefined ? annotationObject.name : _values
        let attrs = annotationObject.threeD.other_attributes
        for (let j = 1; j <= 8; j++) {
          if (attrs['a' + j]) {
            let tmp = this.selectDictLabel(this.attributeNames, annotationObject.name + '_a' + j + '_3d')
            let markType = 'cube'
            let markTypeAttr = this.selectDictLabel(this.attributeNames, markType + '_a' + j + '_3d')
            let traditional = this.selectDictLabel(this.attributeNames, 'a' + j + '_3d')
            if (tmp) {
              try {
                let jsonObject = JSON.parse(tmp)
                _values = jsonObject.values[attrs['a' + j]]
                if (_values === undefined) labelContent += '-' + attrs['a' + j]
                else labelContent += '-' + _values
              } catch (e) {}
            } else if (markTypeAttr) {
              try {
                let jsonObject = JSON.parse(markTypeAttr)
                _values = jsonObject.values[attrs['a' + j]]
                if (_values === undefined) labelContent += '-' + attrs['a' + j]
                else labelContent += '-' + _values
              } catch (e) {}
            } else if (traditional) {
              try {
                let jsonObject = JSON.parse(traditional)
                _values = jsonObject.values[attrs['a' + j]]
                if (_values === undefined) labelContent += '-' + attrs['a' + j]
                labelContent += '-' + _values
              } catch (e) {}
            }
          }
        }

        for (let j = 1; j <= 8; j++) {
          if (attrs['b' + j]) {
            let tmp = this.selectDictLabel(this.attributeNames, annotationObject.name + '_b' + j + '_3d')
            let markType = 'cube'
            let markTypeAttr = this.selectDictLabel(this.attributeNames, markType + '_b' + j + '_3d')
            let traditional = this.selectDictLabel(this.attributeNames, 'b' + j + '_3d')
            if (tmp) {
              try {
                let jsonObject = JSON.parse(tmp)
                _values = jsonObject.values[attrs['b' + j]]
                if (_values === undefined) labelContent += '-' + attrs['b' + j]
                labelContent += '-' + _values
              } catch (e) {}
            } else if (markTypeAttr) {
              try {
                let jsonObject = JSON.parse(markTypeAttr)
                _values = jsonObject.values[attrs['b' + j]]
                if (_values === undefined) labelContent += '-' + attrs['b' + j]
                labelContent += '-' + _values
              } catch (e) {}
            } else if (traditional) {
              try {
                let jsonObject = JSON.parse(traditional)
                _values = jsonObject.values[attrs['b' + j]]
                if (_values === undefined) labelContent += '-' + attrs['b' + j]
                labelContent += '-' + _values
              } catch (e) {}
            }
          }
        }
        const text = document.createElement('div')
        text.className = 'label'
        // text.style.color = 'rgb(255,255,0)'
        text.style.color = fillStyle_r
        text.textContent = labelContent
        const label = new CSS2DObject(text)
        label.position.x = this.scene.points.geometry.attributes.position.array[3 * pointsIndex[0]]
        label.position.y = this.scene.points.geometry.attributes.position.array[3 * pointsIndex[0] + 1]
        label.position.z = this.scene.points.geometry.attributes.position.array[3 * pointsIndex[0] + 2]
        label.tag = 'des_label'
        label.visible = this.showLabel
        this.scene.add(label)
        this.lineList.push(label)
        annotationObject.label = label
      } else {
        annotationObject.label.visible = true
      }
      this.scene.points.geometry.attributes.color.needsUpdate = true
      this.splitObjects.set(annotationObject.mMarkAnnotationId, annotationObject)
    },
    hideSplitInstance(annotationObject, playModel) {
      let pointsIndex = annotationObject.threeD.bndbox.x.split(',')
      pointsIndex.forEach((index) => {
        // let intensity = this.scene.points.geometry.attributes.intensities.array[index]
        this.scene.points.geometry.attributes.color.array[3 * index] =
          this.scene.points.geometry.attributes.originalColor.array[3 * index]
        this.scene.points.geometry.attributes.color.array[3 * index + 1] =
          this.scene.points.geometry.attributes.originalColor.array[3 * index + 1]
        this.scene.points.geometry.attributes.color.array[3 * index + 2] =
          this.scene.points.geometry.attributes.originalColor.array[3 * index + 2]
        // this.scene.points.geometry.attributes.originalColor.array[3 * index] = intensity * parseInt(fillStyle[0]) / 255.0;
        // this.scene.points.geometry.attributes.originalColor.array[3 * index + 1] = intensity * parseInt(fillStyle[1]) / 255.0;
        // this.scene.points.geometry.attributes.originalColor.array[3 * index + 2] = intensity * parseInt(fillStyle[2]) / 255.0;
      })
      if (annotationObject.label) annotationObject.label.visible = false

      this.scene.points.geometry.attributes.color.needsUpdate = true
    },
    // 添加矩形框数据
    addCube(playModel = false) {
      this.elements_3D = []
      this.remarkLabelList = new Array()

      let _range = this.selectDictLabel(this.attributeNames, 'range')
      if (_range) {
        if (_range.startsWith('radius:')) {
          let radius = parseFloat(_range.replace('radius:', ''))
          this.add_range_box(radius)
        } else {
          let xRange = 0
          let yRange = 0
          if (_range.indexOf(';') != -1) {
            let ranges = _range.split(';')
            for (let rangeIndex = 0; rangeIndex < ranges.length; rangeIndex++) {
              _range = ranges[rangeIndex]
              if (_range.indexOf(',') != -1) {
                xRange = parseFloat(_range.split(',')[0])
                yRange = parseFloat(_range.split(',')[1])
              } else {
                xRange = parseFloat(_range)
                yRange = parseFloat(_range)
              }
              this.drawRange(xRange, yRange)
            }
          } else {
            if (_range.indexOf(',') != -1) {
              xRange = parseFloat(_range.split(',')[0])
              yRange = parseFloat(_range.split(',')[1])
            } else {
              xRange = parseFloat(_range)
              yRange = parseFloat(_range)
            }
            this.drawRange(xRange, yRange)
          }
        }
      }

      if (this.annotation && this.annotation.object) {
        for (let i = 0; i < this.annotation.object.length; i++) {
          let fillStyle = this.selectDictLabel(this.colorNames, this.annotation.object[i].name)
          if (!fillStyle) {
            fillStyle = 'rgb(255,255,255)'
          }

          let current = this.annotation.object[i].threeD.bndbox
          if (current.z === 'split') {
            this.addSplitInstance(this.annotation.object[i], playModel)
            continue
          } else if (current.z === 'pointLine') {
            let annotationObject = this.annotation.object[i]

            let labelContent = ''
            let _values = undefined
            if (this.selectDictLabel(this.attributeNames, 'labelName')) {
              try {
                let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'labelName'))
                _values = jsonObject.values[annotationObject.name]
              } catch (e) {
                console.log(e)
              }
            }
            labelContent += _values === undefined ? annotationObject.name : _values
            let markType = 'cube'
            if (annotationObject.threeD.bndbox.z === 'split') {
              markType = 'split'
            }
            let attrs = annotationObject.threeD.other_attributes
            if (attrs.labels) {
              try {
                attrs = JSON.parse(attrs.labels)
              } catch {}
            }
            for (let j = 1; j <= 8; j++) {
              if (attrs['a' + j] && attrs['a' + j] != 'null') {
                try {
                  let pre = ''
                  if (this.selectDictLabel(this.attributeNames, annotationObject.name + '_a' + j + '_3d')) {
                    pre = annotationObject.name + '_'
                  } else if (this.selectDictLabel(this.attributeNames, markType + '_a' + j + '_3d')) {
                    pre = markType + '_'
                  }
                  let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, pre + 'a' + j + '_3d'))
                  if (jsonObject) {
                    let _values = jsonObject.values['' + attrs['a' + j]]
                    if (_values === undefined) labelContent += '-' + attrs['a' + j]
                    else labelContent += '-' + _values
                  }
                } catch (e) {}
              }
            }
            for (let j = 1; j <= 8; j++) {
              if (attrs['b' + j] && attrs['b' + j] != 'null') {
                try {
                  let pre = ''
                  if (this.selectDictLabel(this.attributeNames, annotationObject.name + '_b' + j + '_3d')) {
                    pre = annotationObject.name + '_'
                  } else if (this.selectDictLabel(this.attributeNames, markType + '_b' + j + '_3d')) {
                    pre = markType + '_'
                  }
                  let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, pre + 'b' + j + '_3d'))
                  if (jsonObject) {
                    let _values = jsonObject.values['' + attrs['b' + j]]
                    if (_values === undefined) labelContent += '-' + attrs['b' + j]
                    else labelContent += '-' + _values
                  }
                } catch (e) {}
              }
            }

            this.annotation.object[i].labelContent = labelContent
            addPointsLineInstance(this.annotation.object[i], fillStyle, this.scene, this.track)
            continue
          }
          let box = null
          if (this.annotation.object[i].threeD.other_attributes.labels) {
            try {
              box = JSON.parse(this.annotation.object[i].threeD.other_attributes.labels)['psr']
            } catch {}
          }
          if (!box) {
            let x = current.x.split(';')
            let y = current.y.split(';')
            let z = current.z.split(';')
            let eightPoints = []
            for (let p = 0; p < 8; p++) {
              eightPoints.push(parseFloat(x[p]))
              eightPoints.push(parseFloat(y[p]))
              eightPoints.push(parseFloat(z[p]))
            }
            box = xyz_to_psr(eightPoints)
            let tmp = box.scale.x
            box.scale.x = box.scale.y
            box.scale.y = tmp
            box.rotation.z -= Math.PI / 2
          }

          const assets = {
            mMarkAnnotationId: this.annotation.object[i].mMarkAnnotationId,
            mQaResultId: this.mQaResultId,
            name: this.annotation.object[i].name,
            fileName: this.fileList[this.currentIndex].fileId,
          }

          let jsonAttributes = {}
          try {
            if (this.annotation.object[i].threeD.other_attributes.labels)
              jsonAttributes = JSON.parse(this.annotation.object[i].threeD.other_attributes.labels)
          } catch {}

          for (let ii = 1; ii <= 8; ii++) {
            assets['a' + ii] = this.annotation.object[i].threeD.other_attributes['a' + ii]
            assets['b' + ii] = this.annotation.object[i].threeD.other_attributes['b' + ii]
            if (jsonAttributes['a' + ii]) {
              assets['a' + ii] = jsonAttributes['a' + ii]
            }
            if (jsonAttributes['b' + ii]) {
              assets['b' + ii] = jsonAttributes['b' + ii]
            }
          }
          if (jsonAttributes['uuid']) assets['uuid'] = jsonAttributes['uuid']
          if (jsonAttributes['globalId']) assets['globalId'] = jsonAttributes['globalId']

          const cubeMesh = this.createCubeMesh(box, assets)

          this.cubeList.push(cubeMesh)
          this.cubeInstances.push(cubeMesh)
        }
      }
      for (let prop in this.elementsRemark) {
        if (prop.startsWith('ball') && this.elementsRemark[prop].mType === '3d') {
          let x = this.elementsRemark[prop].x
          let y = this.elementsRemark[prop].y
          let z = this.elementsRemark[prop].z
          let remark = this.elementsRemark[prop].remark
            ? this.elementsRemark[prop].remark
            : this.elementsRemark[prop].errorType
          this.addRemarkLabel(x, y, z, remark)
        }
      }
    },
    createCubeMesh(box, assets) {
      let description = ''
      let labelContent = ''
      description = assets.name + ':3:cube;'
      let _values = undefined
      if (this.selectDictLabel(this.attributeNames, 'labelName')) {
        try {
          let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'labelName'))
          _values = jsonObject.values[assets.name]
        } catch (e) {
          console.log(e)
        }
      }
      labelContent += _values === undefined ? assets.name : _values
      for (let i = 1; i <= 9; i++) {
        if (assets['a' + i]) {
          description += assets['a' + i] + ';'
          try {
            let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'a' + i + '_3d'))
            _values = jsonObject.values[assets['a' + i]]
            if (!jsonObject.typeDesc) continue
            if (_values === undefined) labelContent += '-' + assets['a' + i]
            else labelContent += '-' + _values
          } catch (e) {}
        }
      }

      let fillStyle = this.selectDictLabel(this.colorNames, assets.name)
      if (!fillStyle) {
        fillStyle = 'rgb(255,255,255)'
      }

      const geometry = new THREE.BoxGeometry(1, 1, 1, 1, 1, 1)
      const material = new THREE.MeshBasicMaterial({
        color: fillStyle,
        opacity: 0.2,
        transparent: true,
      })
      const cubeMesh = new THREE.Mesh(geometry, material)

      cubeMesh.name = 'Box'
      cubeMesh.tag = description
      // cubeMesh.tag += '长：' + box.scale.x + ', ' + '宽：' + box.scale.y + ', ' + '高：' + box.scale.z
      cubeMesh.position.copy(box.position)
      cubeMesh.scale.copy(box.scale)
      cubeMesh.rotation.x = box.rotation.x
      cubeMesh.rotation.y = box.rotation.y
      cubeMesh.rotation.z = box.rotation.z
      cubeMesh.assets = assets
      if (assets['uuid']) cubeMesh.uuid = assets['uuid']
      else cubeMesh.uuid = THREE.MathUtils.generateUUID()
      cubeMesh.globalId = assets['globalId'] ? assets['globalId'] : THREE.MathUtils.generateUUID()
      assets['globalId'] = cubeMesh.globalId
      cubeMesh.changed = false
      cubeMesh.fillStyle = fillStyle

      const boxHelper = new CubeHelper(cubeMesh, fillStyle)
      cubeMesh.boxHelper = boxHelper
      cubeMesh.eightPoints = cubeMesh.boxHelper.update()

      this.scene.add(cubeMesh)
      this.scene.add(boxHelper)

      const text = document.createElement('div')
      text.className = 'label'
      text.style.color = 'rgb(255,255,255)'
      text.textContent = labelContent
      const label = new CSS2DObject(text)
      label.position.copy(box.position)
      label.tag = 'des_label'
      label.visible = this.showLabel
      this.scene.add(label)
      this.lineList.push(label)

      cubeMesh.label = label

      cubeMesh.drawDirectLine = () => {
        if (cubeMesh.arrow) {
          this.scene.remove(cubeMesh.arrow)
          this.scene.remove(cubeMesh.directLine)
        }

        const direction = this.createDirectLine(cubeMesh, fillStyle)

        cubeMesh.arrow = direction.cone
        cubeMesh.directLine = direction.directLine
      }

      cubeMesh.drawDirectLine()

      cubeMesh.hide = () => {
        cubeMesh.arrow.visible = false
        cubeMesh.directLine.visible = false
        cubeMesh.label.visible = false
        cubeMesh.visible = false
      }

      cubeMesh.show = () => {
        cubeMesh.arrow.visible = true
        cubeMesh.directLine.visible = true
        cubeMesh.label.visible = true
        cubeMesh.visible = true
      }

      cubeMesh.translate_box = (viewName, delta) => {
        switch (viewName) {
          case 'x':
            cubeMesh.position.x += delta * Math.cos(cubeMesh.rotation.z)
            cubeMesh.position.y += delta * Math.sin(cubeMesh.rotation.z)
            break
          case 'y':
            cubeMesh.position.x += delta * Math.cos(Math.PI / 2 + cubeMesh.rotation.z)
            cubeMesh.position.y += delta * Math.sin(Math.PI / 2 + cubeMesh.rotation.z)
            break
          case 'z':
            cubeMesh.position.z += delta
            break
        }
        cubeMesh.eightPoints = cubeMesh.boxHelper.update()
        this.drawEightPoints(cubeMesh.eightPoints)
        cubeMesh.drawDirectLine()
        cubeMesh.changed = true
      }

      cubeMesh.scale_box = (viewName, delta) => {
        cubeMesh.scale[viewName] += delta[viewName]
        cubeMesh.eightPoints = cubeMesh.boxHelper.update()
        this.drawEightPoints(cubeMesh.eightPoints)
        cubeMesh.drawDirectLine()
        cubeMesh.changed = true
      }

      cubeMesh.onDirectionChanged = (theta, sticky, viewPrefix) => {
        var _tempQuaternion = new THREE.Quaternion()
        if (viewPrefix === 'z') {
          var rotationAxis = new THREE.Vector3(0, 0, 1)
          cubeMesh.quaternion.multiply(_tempQuaternion.setFromAxisAngle(rotationAxis, theta)).normalize()
        } else if (viewPrefix === 'y') {
          var rotationAxis = new THREE.Vector3(0, 1, 0)

          /*
                NOTE:
                the front/end subview is different from top/side view,
                that we look at the reverse direction of y-axis it's end view acturally.
                we could project front-view, but the translation (left, right) will be in reverse direction of top view.
                that would be frustrating.
              */
          cubeMesh.quaternion.multiply(_tempQuaternion.setFromAxisAngle(rotationAxis, -theta)).normalize()
        } else if (viewPrefix === 'x') {
          var rotationAxis = new THREE.Vector3(1, 0, 0)
          cubeMesh.quaternion.multiply(_tempQuaternion.setFromAxisAngle(rotationAxis, theta)).normalize()
        }
        cubeMesh.eightPoints = cubeMesh.boxHelper.update()
        this.drawEightPoints(cubeMesh.eightPoints)
        cubeMesh.drawDirectLine()
        cubeMesh.focusInSideViews()
        cubeMesh.changed = true
      }

      cubeMesh.focusInSideViews = () => {
        this.focusInSideViews(cubeMesh)
      }

      cubeMesh.toDBObject = () => {
        let x = ''
        let y = ''
        let z = ''

        for (let ii = 0; ii < 8; ii++) {
          x += cubeMesh.eightPoints[ii * 3].toFixed(5) + ';'
          y += cubeMesh.eightPoints[ii * 3 + 1].toFixed(5) + ';'
          z += cubeMesh.eightPoints[ii * 3 + 2].toFixed(5) + ';'
        }

        const ret = {
          mMarkAnnotationId: cubeMesh.assets.mMarkAnnotationId,
          mQaResultId: cubeMesh.assets.mQaResultId,
          name: cubeMesh.assets.name,
          x: x,
          y: y,
          z: z,
          fileType: '3d',
          annotationType: 'cube',
          fileName: cubeMesh.assets.fileName,
          rotateTheta: null,
          orientTheta: cubeMesh.rotation.z,
        }
        let labels = {}
        for (let ii = 1; ii <= 8; ii++) {
          ret['a' + ii] = cubeMesh.assets['a' + ii]
          ret['b' + ii] = cubeMesh.assets['b' + ii]
          labels['a' + ii] = cubeMesh.assets['a' + ii]
          labels['b' + ii] = cubeMesh.assets['b' + ii]
        }
        labels.psr = {}
        labels.psr.position = cubeMesh.position
        labels.psr.scale = cubeMesh.scale
        labels.psr.rotation = { x: cubeMesh.rotation.x, y: cubeMesh.rotation.y, z: cubeMesh.rotation.z }
        labels.quaternion = {
          x: cubeMesh.quaternion.x,
          y: cubeMesh.quaternion.y,
          z: cubeMesh.quaternion.z,
          w: cubeMesh.quaternion.w,
        }
        labels.uuid = cubeMesh.uuid
        labels.globalId = cubeMesh.globalId
        labels = JSON.stringify(labels)
        ret.labels = labels
        return ret
      }

      return cubeMesh
    },
    createDirectLine(box, fillStyle) {
      let orient = [box.scale.x * Math.cos(box.rotation.z), box.scale.x * Math.sin(box.rotation.z), 0.0]
      let pos1 = new THREE.Vector3(box.position.x, box.position.y, box.position.z)
      let pos2 = new THREE.Vector3(pos1.x + orient[0], pos1.y + orient[1], pos1.z + orient[2])

      const circleLen = box.scale.x / 5

      let lineGeometry = this.track(new THREE.Geometry())
      let lineMaterial = this.track(
        new THREE.LineBasicMaterial({
          color: fillStyle,
        })
      )
      lineGeometry.vertices.push(pos1, pos2)
      let directLine = this.track(new THREE.Line(lineGeometry, lineMaterial))
      this.lineList.push(directLine)
      this.scene.add(directLine)

      // 四棱锥
      let geometryCone = this.track(new THREE.ConeBufferGeometry(circleLen / 12, circleLen / 3, 8))

      let materialCone = this.track(new THREE.MeshBasicMaterial({ color: fillStyle }))
      let cone = new THREE.Mesh(geometryCone, materialCone)
      cone.position.copy(pos2)
      cone.rotation.x = box.rotation.x
      cone.rotation.y = box.rotation.y
      cone.rotation.z = box.rotation.z - Math.PI / 2
      this.scene.add(cone)
      this.lineList.push(cone)
      return { cone, directLine }
    },
    drawRange(xRange, yRange) {
      let lineGeometry = this.track(new THREE.Geometry())
      let lineMaterial = this.track(new THREE.LineBasicMaterial({ color: 'rgb(42,42,42)' }))
      let pos1 = new THREE.Vector3(xRange, yRange, 0)
      let pos2 = new THREE.Vector3(xRange, 0 - yRange, 0)
      let pos3 = new THREE.Vector3(0 - xRange, 0 - yRange, 0)
      let pos4 = new THREE.Vector3(0 - xRange, yRange, 0)
      lineGeometry.vertices.push(pos1, pos2)
      let directLine = new THREE.Line(lineGeometry, lineMaterial)
      this.lineList.push(directLine)
      this.scene.add(directLine)
      lineGeometry.vertices.push(pos2, pos3)
      directLine = new THREE.Line(lineGeometry, lineMaterial)
      this.lineList.push(directLine)
      this.scene.add(directLine)
      lineGeometry.vertices.push(pos3, pos4)
      directLine = new THREE.Line(lineGeometry, lineMaterial)
      this.lineList.push(directLine)
      this.scene.add(directLine)
      lineGeometry.vertices.push(pos1, pos4)
      directLine = new THREE.Line(lineGeometry, lineMaterial)
      this.lineList.push(directLine)
      this.scene.add(directLine)
    },
    calCos(a, b) {
      // 点积
      let dotProduct = a[0] * b[0] + a[1] * b[1]
      let d = Math.sqrt(a[0] * a[0] + a[1] * a[1]) * Math.sqrt(b[0] * b[0] + b[1] * b[1])
      return dotProduct / d
    },
    // 矩形框内部的点渲染
    keypointsRender(x, y, z, vertices_2d, playModel = false, highLightCubePoints = null) {
      function GetCross(p1, p2, p) {
        return (p2.x - p1.x) * (p.y - p1.y) - (p.x - p1.x) * (p2.y - p1.y)
      }
      function IsPointInMatrix(p1, p2, p3, p4, p) {
        let isPointIn = GetCross(p1, p2, p) * GetCross(p3, p4, p) >= 0 && GetCross(p2, p3, p) * GetCross(p4, p1, p) >= 0
        return isPointIn
      }
      if (!playModel) {
        let geometry_temp = this.track(new THREE.BufferGeometry())
        let positions_temp = []
        let colors_temp = []
        let count = 0
        let max_x = Math.max(x[0], x[1], x[2], x[3])
        let max_y = Math.max(y[0], y[1], y[2], y[3])
        let min_x = Math.min(x[0], x[1], x[2], x[3])
        let min_y = Math.min(y[0], y[1], y[2], y[3])
        let min_z = Math.min(z[0], z[4])
        let max_z = Math.max(z[0], z[4])
        for (let i = 0; i < this.scene.points.geometry.attributes.position.array.length / 3; i++) {
          if (
            this.scene.points.geometry.attributes.position.array[3 * i] > max_x ||
            this.scene.points.geometry.attributes.position.array[3 * i] < min_x
          )
            continue
          if (
            this.scene.points.geometry.attributes.position.array[3 * i + 1] > max_y ||
            this.scene.points.geometry.attributes.position.array[3 * i + 1] < min_y
          )
            continue
          if (
            this.scene.points.geometry.attributes.position.array[3 * i + 2] > max_z ||
            this.scene.points.geometry.attributes.position.array[3 * i + 2] < min_z
          )
            continue
          let pointA_2d = new THREE.Vector2(
            this.scene.points.geometry.attributes.position.array[3 * i],
            this.scene.points.geometry.attributes.position.array[3 * i + 1]
          )
          if (IsPointInMatrix(vertices_2d[0], vertices_2d[1], vertices_2d[2], vertices_2d[3], pointA_2d)) {
            if (highLightCubePoints) {
              colors_temp.push(
                this.scene.points.geometry.attributes.color.array[3 * i],
                this.scene.points.geometry.attributes.color.array[3 * i + 1],
                this.scene.points.geometry.attributes.color.array[3 * i + 2]
              )
            } else {
              this.scene.points.geometry.attributes.color.array[3 * i] = 1.0
              this.scene.points.geometry.attributes.color.array[3 * i + 1] = 0.0
              this.scene.points.geometry.attributes.color.array[3 * i + 2] = 0.0
              colors_temp.push(1, 1, 1)
            }
            positions_temp.push(
              parseFloat(this.scene.points.geometry.attributes.position.array[3 * i]),
              parseFloat(this.scene.points.geometry.attributes.position.array[3 * i + 1]),
              parseFloat(this.scene.points.geometry.attributes.position.array[3 * i + 2])
            )
            count++
          }
        }
        geometry_temp.setAttribute('position', new THREE.Float32BufferAttribute(positions_temp, 3))
        geometry_temp.setAttribute('color', new THREE.Float32BufferAttribute(colors_temp, 3))
        geometry_temp.computeBoundingSphere()
        let canvas_temp = document.createElement('canvas')
        canvas_temp.width = 100
        canvas_temp.height = 100
        let context = canvas_temp.getContext('2d')
        context.fillStyle = 'rgb(255,255,255)'
        context.arc(50, 50, 45, 0, 2 * Math.PI)
        context.fill()
        let texture = this.track(new THREE.Texture(canvas_temp))
        texture.needsUpdate = true
        let material_temp = this.track(
          new THREE.PointsMaterial({
            size: 3,
            vertexColors: THREE.VertexColors,
            depthTest: false,
            fog: false,
            map: texture,
          })
        )

        material_temp.sizeAttenuation = false
        return [geometry_temp, material_temp, count]
      }
      return null
    },
    // 高亮选中的点
    showSelectedPoint(x, y, z) {
      let canvas_temp0 = document.createElement('canvas')
      canvas_temp0.width = 100
      canvas_temp0.height = 100
      let context0 = canvas_temp0.getContext('2d')
      context0.fillStyle = '#ffffff'
      context0.arc(50, 50, 45, 0, 2 * Math.PI)
      context0.fill()
      let texture0 = this.track(new THREE.Texture(canvas_temp0))
      texture0.needsUpdate = true
      let geometry = this.track(new THREE.Geometry())
      let p1 = new THREE.Vector3(x, y, z)
      geometry.vertices.push(p1)
      let material = this.track(
        new THREE.PointsMaterial({
          color: 0xffffff,
          size: 10,
          depthTest: false,
          map: texture0,
        })
      )
      material.sizeAttenuation = false
      material.fog = false
      this.selectPointObject = new THREE.Points(geometry, material)
      this.scene.add(this.selectPointObject)
    },
    render() {
      if (!this.renderer) {
        return
      }

      this.renderRequested = undefined
      const canvas = this.renderer.domElement
      if (this.resizeRendererToDisplaySize(this.renderer)) {
        this.camera.aspect = canvas.clientWidth / canvas.clientHeight
        this.camera.updateProjectionMatrix()
        this.renderer.setSize(canvas.clientWidth, canvas.clientHeight)
      }
      this.renderer.setClearColor(0x000000, 0)
      this.renderer.setViewport(0, 0, canvas.clientWidth, canvas.clientHeight)
      this.controls.update()
      this.renderer.render(this.scene, this.camera)
      this.labelRenderer.render(this.scene, this.camera)
      this.renderer.setScissorTest(false)

      if (this.showViews) {
        this.viewsRender()
      }
    },
    viewsRender() {
      if (!this.renderer) {
        return
      }

      const rect = this.renderer.domElement.getBoundingClientRect()
      const windowWidth = rect.width
      const windowHeight = rect.height
      for (let ii = 0; ii < views.length; ++ii) {
        const view = views[ii]
        const camera = view.camera

        const left = Math.floor(windowWidth * view.left)
        const bottom = Math.floor(windowHeight * view.bottom)
        const width = Math.ceil(windowWidth * view.width)
        const height = Math.ceil(windowHeight * view.height)
        if (this.resizeRendererToDisplaySize(this.renderer)) {
          camera.aspect = width / height
          camera.updateProjectionMatrix()
        }

        view.viewport = {
          left: windowWidth * view.left,
          bottom: windowHeight - windowHeight * view.bottom,
          width: windowWidth * view.width,
          height: windowHeight * view.height,
          zoom_ratio: view.zoom_ratio,
        }

        this.renderer.setViewport(left, bottom, width, height)
        this.renderer.setScissor(left, bottom, width, height)
        this.renderer.setScissorTest(true)
        this.renderer.setClearColor(view.background)

        this.renderer.render(this.scene, camera)
        this.renderer.setScissorTest(false)
      }
    },
    requestRenderIfNotRequested(e) {
      if (this.labelTool && this.labelTool.controlsChange) {
        this.labelTool.controlsChange(e)
      }
      if (!this.renderRequested) {
        this.renderRequested = true
        requestAnimationFrame(this.render)
      }
    },
    resizeRendererToDisplaySize(renderer) {
      const canvas = renderer.domElement
      const width = canvas.clientWidth
      const height = canvas.clientHeight
      const needResize = canvas.width !== width || canvas.height !== height
      if (needResize) {
        renderer.setSize(width, height, false)
      }
      return needResize
    },
    // 重新渲染3D视窗内的批注图标
    reRender() {
      for (let i = 0; i < this.remarkLabelList.length; i++) {
        if (this.elementsRemark[this.remarkLabelList[i].missId]) {
          this.scene.add(this.remarkLabelList[i])
        } else {
          this.scene.remove(this.remarkLabelList[i])
        }
      }
      // this.renderer.render(this.scene, this.camera)
      // this.labelRenderer.render(this.scene, this.camera)
      this.render()
    },
    onWindowResize() {
      if (this.camera) {
        // this.camera.aspect = this.container.offsetWidth / this.container.offsetHeight
        // this.renderer.setSize(this.container.offsetWidth, this.container.offsetHeight)
        // this.labelRenderer.setSize(this.container.offsetWidth, this.container.offsetHeight)
        // this.camera.updateProjectionMatrix()
        // this.renderer.render(this.scene, this.camera)
        // this.labelRenderer.render(this.scene, this.camera)
        this.render()
      }
    },
    // 鼠标按下事件处理
    onMouseDown(event) {
      this.mouseDown = true
      // this.hideManipulator()
      event.preventDefault()

      if (views[0].camera) {
        views[0].camera.box = null
        views[1].camera.box = null
        views[2].camera.box = null
      }

      if (this.labelTool) {
        this.labelTool.onMouseDown(event)
        return
      }

      this.scene.remove(this.selectPointObject)
      let rect = this.renderer.domElement.getBoundingClientRect()
      this.mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1
      this.mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1
      this.raycaster.setFromCamera(this.mouse, this.camera)
      let intersects = this.raycaster.intersectObjects(this.cubeInstances, true)
      if (this.remarkBallPoint.visible) {
        let x = this.remarkBallPoint.position.x
        let y = this.remarkBallPoint.position.y
        let z = this.remarkBallPoint.position.z

        const remarkLabel = this.addRemarkLabel(x, y, z, '')

        let missId = 'lou-3d-' + remarkLabel.id
        remarkLabel.missId = missId
        this.selectedObject.a1 = missId
        this.selectedObject.type = '3d'
        this.selectedObject.errorType = 'miss_mark'
        this.selectedObject.elementInstance = remarkLabel
        this.selectedObject.mPoint = {
          x: x,
          y: y,
          z: z,
        }
        this.showSelectedPoint(x, y, z)
        this.handleElementComments(missId, this.selectedObject)
        this.remarkBallPoint.visible = false
      }

      // 点云目标框检测处理
      else if (intersects.length > 0) {
        if (intersects[0].object.type == 'Mesh') {
          if (this.INTERSECTED) {
            if (this.selectionBox.labelTool === 'cube') {
            }
            let _array = intersects[0].object.tag.split(';')
            this.selectedObject.mMarkAnnotationId = intersects[0].object.assets.mMarkAnnotationId
            this.selectedObject.mQaResultId = intersects[0].object.assets.mQaResultId
            this.selectedObject.fileName = intersects[0].object.assets.fileName
            this.selectedObject.fileType = '3d'
            this.selectedObject.type = '3d'
            this.selectedObject.name = intersects[0].object.assets.name
            for (let ii = 1; ii <= 8; ii++) {
              this.selectedObject['a' + ii] = intersects[0].object.assets['a' + ii]
              this.selectedObject['b' + ii] = intersects[0].object.assets['b' + ii]
              this.selectedObject.attributes.push(this.selectedObject['a' + ii])
              this.selectedObject.attributes.push(this.selectedObject['b' + ii])
            }
            this.selectedObject.labels = intersects[0].object.toDBObject().labels
            this.selectedObject.markType = 'cube'
            this.selectedObject.remark = this.elementsRemark['ball-' + _array[1] + '-3d']
              ? this.elementsRemark['ball-' + _array[1] + '-3d'].remark
              : ''
            this.selectedObject.errorType = this.elementsRemark['ball-' + _array[1] + '-3d']
              ? this.elementsRemark['ball-' + _array[1] + '-3d'].errorType
              : ''
            this.selectedObject.mPoint = intersects[0].object.position
            this.selectedObject.elementInstance = intersects[0].object.remarkLabel
            this.selectedObject.attributes = []
            this.selectedObject.cubeMesh = intersects[0].object
            this.cubeMap.set(this.selectedObject.a1, intersects[0].object)

            this.sync_highlight_objects('3d', this.selectedObject, intersects[0].object)

            for (let ii = 0; ii < views.length; ++ii) {
              views[ii].zoom_ratio = 1
            }
            if (this.showViews && !this.checkrole(['qa'])) {
              this.showManipulator()
            }
            this.focusInSideViews(intersects[0].object)
            this.projectedCube = intersects[0].object.uuid
            this.invokeImageProjection()
            return
          }
        }
      }

      // 点云分割目标处理
      intersects = this.raycaster.intersectObjects(this.splitPoints, true)
      if (intersects.length > 0) {
        if (intersects[0].object != this.INTERSECTED) {
          if (intersects[0].object.mMarkAnnotationId && intersects[0].object.annotationObject) {
            this.focusObject(intersects[0].object.annotationObject)
            let _array = intersects[0].object.tag.split(';')
            this.selectedObject.mMarkAnnotationId = intersects[0].object.mMarkAnnotationId
            this.selectedObject.name = _array[0].split(':')[0]
            this.selectedObject.a1 = _array[1]
            this.selectedObject.a2 = _array[2]
            this.selectedObject.a3 = _array[3]
            this.selectedObject.a4 = _array[4]
            this.selectedObject.a5 = _array[5]
            this.selectedObject.a6 = _array[6]
            this.selectedObject.a7 = _array[7]
            this.selectedObject.a8 = _array[8]
            this.selectedObject.remark = this.elementsRemark['ball-' + _array[1] + '-3d']
              ? this.elementsRemark['ball-' + _array[1] + '-3d'].remark
              : ''
            this.selectedObject.errorType = this.elementsRemark['ball-' + _array[1] + '-3d']
              ? this.elementsRemark['ball-' + _array[1] + '-3d'].errorType
              : ''
            this.selectedObject.mPoint = intersects[0].object.position
            this.selectedObject.elementInstance = intersects[0].object.remarkLabel
            this.selectedObject.attributes = []
          }
        }
      }

      // 点云车道线目标处理
      if (this.scene.pointsLines && this.scene.pointsLines.length > 0) {
        intersects = this.raycaster.intersectObjects(this.scene.pointsLines, true)
        if (intersects.length > 0) {
          if (intersects[0].object.annotationObject) {
            this.focusObject(intersects[0].object.annotationObject)
            let annotationObject = intersects[0].object.annotationObject
            this.selectedObject.mMarkAnnotationId = annotationObject.mMarkAnnotationId
            this.selectedObject.name = annotationObject.name
            let attrs = annotationObject.threeD.other_attributes
            if (annotationObject.threeD.other_attributes.labels) {
              try {
                attrs = JSON.parse(annotationObject.threeD.other_attributes.labels)
              } catch {}
            }
            for (let j = 1; j <= 8; j++) {
              this.selectedObject['a' + j] = attrs['a' + j]
              this.selectedObject['b' + j] = attrs['b' + j]
            }

            this.selectedObject.attributes = []
          }
        }
      }
    },
    focusInSideViews(selectedBox) {
      if (!this.showViews) return

      document.getElementById('z-view-content').innerHTML =
        '长：' + selectedBox.scale.x.toFixed(2) + ', 宽：' + selectedBox.scale.y.toFixed(2)
      document.getElementById('y-view-content').innerHTML =
        '长：' + selectedBox.scale.x.toFixed(2) + ', 高：' + selectedBox.scale.z.toFixed(2)
      document.getElementById('x-view-content').innerHTML =
        '高：' + selectedBox.scale.z.toFixed(2) + ', 宽：' + selectedBox.scale.y.toFixed(2)

      views[0].camera.box = selectedBox
      views[1].camera.box = selectedBox
      views[2].camera.box = selectedBox

      var p = selectedBox.position
      var r = selectedBox.rotation

      views[0].camera.rotation.x = r.x
      views[0].camera.rotation.y = r.y
      views[0].camera.rotation.z = r.z - Math.PI / 2

      views[0].camera.position.x = p.x
      views[0].camera.position.y = p.y
      views[0].camera.position.z = p.z
      views[0].camera.updateProjectionMatrix()

      var trans_matrix = euler_angle_to_rotate_matrix(r, p)

      views[1].camera.position.x = p.x
      views[1].camera.position.y = p.y
      views[1].camera.position.z = p.z

      var up = matmul2(trans_matrix, [0, 0, 1, 0], 4)
      views[1].camera.up.set(up[0], up[1], up[2])
      var at = matmul2(trans_matrix, [0, 1, 0, 1], 4)

      views[1].camera.lookAt(at[0], at[1], at[2])
      views[1].camera.updateProjectionMatrix()

      views[2].camera.position.x = p.x
      views[2].camera.position.y = p.y
      views[2].camera.position.z = p.z

      var up3 = matmul2(trans_matrix, [0, 0, 1, 0], 4)
      views[2].camera.up.set(up3[0], up3[1], up3[2])
      var at3 = matmul2(trans_matrix, [-1, 0, 0, 1], 4)
      views[2].camera.lookAt(at3[0], at3[1], at3[2])

      views[2].camera.updateProjectionMatrix()

      this.render()

      this.sideViews.selectedBox = selectedBox

      this.sideViews.update_view_handle(selectedBox)

      this.on_wheel('z', 0)
      this.on_wheel('y', 0)
      this.on_wheel('x', 0)
    },
    onMouseUp(event) {
      this.mouseDown = false
      if (this.labelTool) {
        this.labelTool.onMouseUp(event)
      }
    },
    // 鼠标移动事件处理
    onMouseMove(event) {
      if (this.labelTool) {
        if (this.mouseDown) this.labelTool.onMouseDrag(event)
        else this.labelTool.onMouseMove(event)
        return
      }
      if (this.renderer.domElement) {
        event.preventDefault()
        let rect = this.renderer.domElement.getBoundingClientRect()
        this.mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1
        this.mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1

        this.raycaster.setFromCamera(this.mouse, this.camera)
        if (event.ctrlKey) {
          // 验收球位置辅助工具
          const intersects = this.raycaster.intersectObjects([this.scene.points], true)
          if (intersects.length > 0) {
            intersects.sort((a, b) => (a.distanceToRay < b.distanceToRay ? -1 : 1))
            const closer = intersects[0]
            if (closer.object.type == 'Points') {
              this.remarkBallPoint.visible = true
              const array = this.scene.points.geometry.attributes.position.array
              this.remarkBallPoint.position.copy({
                x: array[3 * closer.index],
                y: array[3 * closer.index + 1],
                z: array[3 * closer.index + 2],
              })
              this.remarkBallPoint.pointsCloudIndex = closer.index
            } else {
              this.remarkBallPoint.visible = false
            }
          } else {
            this.remarkBallPoint.visible = false
          }
        } else {
          this.remarkBallPoint.visible = false
          let intersects = this.raycaster.intersectObjects(this.cubeInstances, true)
          if (intersects.length > 0) {
            if (intersects[0].object != this.INTERSECTED) {
              if (intersects[0].object.type == 'Mesh') {
                // this.renderRequested = true;
                // restore previous intersection object (if it exists) to its original color
                if (this.INTERSECTED) this.INTERSECTED.material.color.setHex(this.INTERSECTED.currentHex)
                // store reference to closest object as current intersection object
                this.INTERSECTED = intersects[0].object
                // store color of closest object (for later restoration)
                this.INTERSECTED.currentHex = this.INTERSECTED.material.color.getHex()
                // set a new color for closest object
                this.INTERSECTED.material.color.setHex(0xffff00)

                const message = intersects[0].object.tag
                // if(this.checkrole(['admin']) || this.checkrole(['checker'])) {
                // let worldVector = new THREE.Vector3(
                //   intersects[0].object.geometry.boundingSphere.center.x,
                //   intersects[0].object.geometry.boundingSphere.center.y,
                //   intersects[0].object.geometry.boundingSphere.center.z
                // )
                //世界坐标转标准设备坐标
                // let stdVector = worldVector.project(this.camera)
                // let a = window.innerWidth / 2
                // let b = window.innerHeight / 2
                //标准设备坐标转屏幕坐标x,y
                // let x = Math.round(stdVector.x * a + a)
                // let y = Math.round(-stdVector.y * b + b)
                this.ShowTip(message, event.clientX, event.clientY)
                // }
              } else {
                this.HideTip()
              }
            }
          } else {
            this.HideTip()
            if (this.INTERSECTED) {
              this.INTERSECTED.material.color.setHex(this.INTERSECTED.currentHex)
              this.INTERSECTED = null
            }
          }
        }

        // this.renderer.render(this.scene, this.camera)
        // this.labelRenderer.render(this.scene, this.camera)
        this.render()
      }
    },
    onMouseWheel() {
      // this.renderRequested = true;
    },
    onKeyPress(event) {
      switch (event.key || String.fromCharCode(event.keyCode || event.charCode)) {
        case '+':
          if (this.scene.points && this.scene.points.material.size < 3.8) {
            this.scene.points.material.size *= 1.1
            this.splitPoints.forEach((pointsMesh) => {
              pointsMesh.material.size *= 1.1
              pointsMesh.material.needsUpdate = true
            })
            this.scene.points.material.needsUpdate = true
          }
          break

        case '_':
          if (this.scene.points && this.scene.points.material.size > 1) {
            this.scene.points.material.size /= 1.1
            this.splitPoints.forEach((pointsMesh) => {
              pointsMesh.material.size /= 1.1
              pointsMesh.material.needsUpdate = true
            })
            this.scene.points.material.needsUpdate = true
          }
          break
      }

      Cookies.remove('pointSize')
      Cookies.set('pointSize', this.scene.points.material.size, { expires: 30 })
      this.render()

      if (event.shiftKey && (event.key === 'B' || event.key === 'B')) {
        this.invokeImageProjection()
      } else if (event.shiftKey && (event.key === 'X' || event.key === 'x')) {
        const cubeMesh = this.selectedObject.cubeMesh
        if (cubeMesh) {
          this.$confirm('确定删除选中的立体框吗？', '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning',
          }).then(() => {
            this.scene.remove(cubeMesh.boxHelper)
            this.scene.remove(cubeMesh.arrow)
            this.scene.remove(cubeMesh.directLine)
            this.scene.remove(cubeMesh.label)
            this.scene.remove(cubeMesh)
            if (this.highlight_points) {
              this.scene.remove(this.highlight_points)
            }
            let index = -1
            this.cubeInstances.forEach((c) => {
              index++
              if (c.uuid === cubeMesh.uuid) {
                return false
              }
            })
            if (index !== -1) {
              this.cubeInstances.splice(index, 1)
            }
            index = -1
            this.cubeList.forEach((c) => {
              index++
              if (c.uuid === cubeMesh.uuid) {
                return false
              }
            })
            if (index >= 0) {
              this.cubeList.splice(index, 1)
            }
            if (cubeMesh.assets.mMarkAnnotationId) {
              deleteAnnotation(cubeMesh.assets.mMarkAnnotationId).then((res) => {
                if (res.code == '200') {
                  const readValue = this.markAnnotations.get('MA:' + cubeMesh.assets.mQaResultId)
                  if (readValue) {
                    let index = -1
                    for (let ii = 0; ii < readValue.object.length; ii++) {
                      if (readValue.object[ii].mMarkAnnotationId === cubeMesh.assets.mMarkAnnotationId) {
                        index = ii
                        break
                      }
                    }
                    if (index >= 0 && index < readValue.object.length) {
                      readValue.object.splice(index, 1)
                    }
                  }
                }
              })
            }
          })
        }
      }
    },
    invokeImageProjection() {
      this.$get(
        'calib:' + this.mQaResultId,
        (calib) => {
          const params = new Map()
          Object.keys(calib.calib).forEach((k) => {
            if (calib.calib[k + ''].extrinsic) {
              if (this.projectedCube && this.projectedCube === this.selectedObject.cubeMesh.uuid) {
                params.set(k, null)
              } else {
                const ret = box_to_2d_points(this.selectedObject.cubeMesh, calib.calib[k + ''])
                if (ret) {
                  params.set(k, ret)
                }
              }
            }
          })
          this.imageProjection(params, this.selectedObject.cubeMesh.fillStyle, this.selectedObject.cubeMesh.assets)
          if (this.projectedCube && this.projectedCube === this.selectedObject.cubeMesh.uuid) {
            this.projectedCube = null
          } else {
            this.projectedCube = this.selectedObject.cubeMesh.uuid
          }
        },
        () => {}
      )
    },
    // 点云数据转3D点云对象
    loadJsonPCD(pointsCloud) {
      let positions = []
      let color = []
      for (var i = 0; i < pointsCloud.length; i++) {
        let x = pointsCloud[i][0]
        let y = pointsCloud[i][1]
        let z = pointsCloud[i][2]
        positions.push(x, y, z)
        let tmp = colorRender(z, this.renderTypeSelection)
        color.push(tmp[0], tmp[1], tmp[2])
      }
      let canvas_temp0 = document.createElement('canvas')
      canvas_temp0.width = 100
      canvas_temp0.height = 100
      let context0 = canvas_temp0.getContext('2d')
      context0.fillStyle = '#ffffff'
      context0.arc(50, 50, 45, 0, 2 * Math.PI)
      context0.fill()
      let texture0 = this.track(new THREE.Texture(canvas_temp0))
      texture0.needsUpdate = true
      let material = this.track(
        new THREE.PointsMaterial({ size: 2, vertexColors: THREE.VertexColors, depthTest: false, map: texture0 })
      )
      material.color.setHex(0xffffff)
      material.sizeAttenuation = false
      material.vertexColors = THREE.VertexColors
      material.depthTest = false
      material.fog = false
      let geometry = this.track(new THREE.BufferGeometry())
      geometry.attributes.color = new THREE.Float32BufferAttribute(color, 3)
      geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3))
      geometry.computeBoundingSphere()
      return new THREE.Points(geometry, material)
    },
    checkrole(role) {
      return checkRole(role)
    },
    showAttributesText2D(show) {
      this.lineList.forEach((element) => {
        if (element.tag === 'des_label') {
          element.visible = show
        }
      })
      if (this.scene.lineList) {
        this.scene.lineList.forEach((element) => {
          if (element.tag === 'des_label') {
            element.visible = show
          }
        })
      }
      this.scene.showLabel = show
      this.reRender()
    },
    addSplitCallback(parms) {
      if (parms.ret === 'confirm') {
        let fillStyle = this.selectDictLabel(this.colorNames, parms.form.name)
        if (!fillStyle) {
          fillStyle = 'rgb(255,255,0)'
        }
        fillStyle = fillStyle.replace('rgb(', '').replace(')', '').replace(' ', '')
        fillStyle = fillStyle.split(',')
        this.tmpSplitPoints.forEach((index) => {
          let intensity = this.scene.points.geometry.attributes.intensities.array[index]
          this.scene.points.geometry.attributes.color.array[3 * index] = (intensity * parseInt(fillStyle[0])) / 255.0
          this.scene.points.geometry.attributes.color.array[3 * index + 1] =
            (intensity * parseInt(fillStyle[1])) / 255.0
          this.scene.points.geometry.attributes.color.array[3 * index + 2] =
            (intensity * parseInt(fillStyle[2])) / 255.0
        })
        this.tmpMinusSplitPoints.forEach((index) => {
          this.scene.points.geometry.attributes.color.array[3 * index] =
            this.scene.points.geometry.attributes.originalColor.array[3 * index]
          this.scene.points.geometry.attributes.color.array[3 * index + 1] =
            this.scene.points.geometry.attributes.originalColor.array[3 * index + 1]
          this.scene.points.geometry.attributes.color.array[3 * index + 2] =
            this.scene.points.geometry.attributes.originalColor.array[3 * index + 2]
        })
        this.scene.points.geometry.attributes.color.needsUpdate = true
        this.render()
        this.tmpSplitPoints = []
        this.tmpMinusSplitPoints = []
      } else {
      }
    },
    focusObject(annotation) {
      if (annotation.z === 'split') {
        if (this.splitRange) {
          if (this.splitRange.pointsMesh) this.scene.remove(this.splitRange.pointsMesh)
          this.scene.remove(this.splitRange)
        }
        let fillStyle = this.selectDictLabel(this.colorNames, annotation.name)
        if (!fillStyle) {
          fillStyle = 'rgb(255, 255, 0)'
        }
        const vertices = []
        const position = []
        const colors = []
        let zRange = 0
        const pointsIndex = annotation.x.split(',')
        const pointsArray = this.scene.points.geometry.attributes.position
          ? this.scene.points.geometry.attributes.position.array
          : []
        pointsIndex.forEach((i) => {
          i = parseInt(i)
          const vertex = new THREE.Vector3(pointsArray[3 * i], pointsArray[3 * i + 1], pointsArray[3 * i + 2])
          vertices.push(vertex)
          zRange += Math.abs(pointsArray[i + 2])
          position.push(pointsArray[3 * i], pointsArray[3 * i + 1], pointsArray[3 * i + 2])
          let color = fillStyle.replace('rgb(', '').replace(')', '').replace(' ', '').split(',')
          colors.push(parseInt(color[0]) / 255.0, parseInt(color[1]) / 255.0, parseInt(color[2]) / 255.0)
        })

        if (vertices.length === 0) return

        if (zRange == 0 || vertices.length < 4) {
          const v = vertices[vertices.length - 1]
          let vertex = new THREE.Vector3(v.x + 0.001, v.y, v.z)
          vertices.push(vertex)
          vertex = new THREE.Vector3(v.x, v.y + 0.001, v.z)
          vertices.push(vertex)
          vertex = new THREE.Vector3(v.x, v.y, v.z + 0.001)
          vertices.push(vertex)
        }

        const meshMaterial = this.track(
          new THREE.MeshBasicMaterial({
            color: fillStyle,
            opacity: 0.3,
            transparent: true,
          })
        )

        const meshGeometry = this.track(new ConvexGeometry(vertices))
        meshGeometry.computeBoundingSphere()

        this.splitRange = this.track(new THREE.Mesh(meshGeometry, meshMaterial))
        this.splitRange.renderOrder = 1
        this.scene.add(this.splitRange)

        let splitViewMode = this.selectDictLabel(this.attributeNames, 'splitViewMode')
        if (!splitViewMode || splitViewMode !== 'highLight') {
          const geometry = this.track(new THREE.BufferGeometry())
          if (position.length > 0) geometry.setAttribute('position', new THREE.Float32BufferAttribute(position, 3))
          if (colors.length > 0) geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3))
          geometry.computeBoundingSphere()
          let material = this.track(new THREE.PointsMaterial({ size: 8 }))
          material.color.setHex(0xffffff)
          material.sizeAttenuation = false
          material.vertexColors = true
          material.depthTest = false
          material.fog = false
          const pointsMesh = this.track(new THREE.Points(geometry, material))
          this.scene.add(pointsMesh)

          this.splitRange.pointsMesh = pointsMesh
        }

        // const x = this.splitRange.geometry.boundingSphere.center.x
        // const y = this.splitRange.geometry.boundingSphere.center.x
        // const z = this.splitRange.geometry.boundingSphere.center.x

        // const distance = 20 * this.splitRange.geometry.boundingSphere.radius
        // let selectCenterPoint = this.calcCameraOffsetPosition(this.splitRange.geometry.boundingSphere.center, distance)
        // this.controls.target.copy(this.splitRange.geometry.boundingSphere.center)
        // this.camera.position.set(selectCenterPoint.x1, selectCenterPoint.y1, selectCenterPoint.z1)
        // this.camera.lookAt(x, y, z)
        // this.camera.updateMatrix()
        // this.renderer.render(this.scene, this.camera)
        // this.controls.update()
        this.render()
      }
    },
    changeLabelTool(toolName) {
      if (this.labelTool && this.labelTool.name === toolName) {
        return
      }
      if (this.labelTool && this.labelTool.onToggleOut) {
        this.labelTool.onToggleOut()
      }
      this.labelTool = tools[toolName]
      this.labelTool.name = toolName
      const params = {
        scene: this.scene,
        camera: this.camera,
        controls: this.controls,
        renderer: this.renderer,
        labelRenderer: this.labelRenderer,
        track: this.track,
        annotations: {
          points: this.scene.points,
        },
      }
      if (this.labelTool && this.labelTool.onToggleIn) {
        this.labelTool.onToggleIn(params)
        this.labelTool.addNew = this.addSplitMarkAnnotation
      }
      if (toolName) {
        if (toolName === 'split') {
          this.splitObjects.forEach((element) => {
            this.addSplitInstance(element, false)
          })
          this.splitPoints.forEach((element) => {
            element.visible = false
          })
        } else {
          this.splitPoints.forEach((element) => {
            element.visible = true
          })
        }
      } else {
        if (this.selectionBox.labelTool === 'view' || this.selectionBox.labelTool === 'minus') {
          this.selectionBox.labelTool = 'point'
        } else {
          this.selectionBox.labelTool = 'minus'
        }
      }
    },
    renderTypeSelectChanged(newRenderType) {
      this.renderTypeSelection = newRenderType
      this.getPointsCloud(this.fileList, this.currentIndex, this.mQaResultId, false, this.showLabel, null)
    },
    addRemarkLabel(x, y, z, content) {
      const textIcon = ' 验 '
      const div = document.createElement('div')
      const text = document.createElement('div')
      text.className = 'label'
      text.style.color = 'rgb(255,255,255)'
      text.style['background-color'] = 'rgb(255,0,0)'
      text.style['border-radius'] = '50%'
      text.style['text-align'] = 'center'
      text.style['float'] = 'left'
      text.style.fontSize = '20px'
      text.textContent = textIcon
      div.appendChild(text)
      if (content) {
        const subText = document.createElement('span')
        subText.className = 'label'
        subText.style.color = 'rgb(255,255,255)'
        subText.style.fontSize = '12px'
        subText.textContent = content
        div.appendChild(subText)
      }
      const remarkLabel = new CSS2DObject(div)
      remarkLabel.position.x = x
      remarkLabel.position.y = y
      remarkLabel.position.z = z
      remarkLabel.tag = 'des_label'
      remarkLabel.visible = this.showLabel

      this.scene.add(remarkLabel)
      this.lineList.push(remarkLabel)

      return remarkLabel
    },
    viewsInitialize() {
      this.showViews = !this.showViews
      if (this.showViews) {
        if (this.selectedObject.cubeMesh) {
          this.focusInSideViews(this.selectedObject.cubeMesh)
          if (!this.checkrole(['qa'])) {
            this.showManipulator()
          }
        }
      } else {
        this.hideManipulator()
      }
    },
    hideManipulator: function () {
      document.getElementById('z-view-manipulator').style.display = 'none'
      document.getElementById('y-view-manipulator').style.display = 'none'
      document.getElementById('x-view-manipulator').style.display = 'none'
    },
    showManipulator: function () {
      document.getElementById('z-view-manipulator').style.display = 'inline-flex'
      document.getElementById('y-view-manipulator').style.display = 'inline-flex'
      document.getElementById('x-view-manipulator').style.display = 'inline-flex'
    },
    on_wheel(viewType, deltaY) {
      let ii = 0
      if (viewType === 'y') ii = 1
      else if (viewType === 'x') ii = 2
      var view = views[ii]
      var camera = view.camera
      var box = view.camera.box
      if (!box) {
        box = {
          scale: {
            x: 1,
            y: 1,
            z: 1,
          },
        }
      }
      var exp_camera_height
      var exp_camera_width
      var exp_camera_clip

      var multiplier = 1.0
      if (deltaY === 0) {
        multiplier = 1
      } else if (deltaY > 0) {
        multiplier = 1.1
      } else {
        multiplier = 0.9
      }
      view.zoom_ratio *= multiplier

      var view_width = Math.floor(window.innerWidth * view.width)
      var view_height = Math.floor(window.innerHeight * view.height)

      if (ii == 0) {
        exp_camera_height = box.scale.x * 1.5 * view.zoom_ratio
        exp_camera_width = box.scale.y * 1.5 * view.zoom_ratio

        exp_camera_clip = box.scale.z + 0.8
      } else if (ii == 1) {
        exp_camera_width = box.scale.x * 1.5 * view.zoom_ratio
        exp_camera_height = box.scale.z * 1.5 * view.zoom_ratio

        exp_camera_clip = box.scale.y * 1.2
      } else if (ii == 2) {
        exp_camera_width = box.scale.y * 1.5 * view.zoom_ratio
        exp_camera_height = box.scale.z * 1.5 * view.zoom_ratio

        exp_camera_clip = box.scale.x * 1.2
      }

      if (exp_camera_width / exp_camera_height > view_width / view_height) {
        exp_camera_height = (exp_camera_width * view_height) / view_width
      } else {
        exp_camera_width = (exp_camera_height * view_width) / view_height
      }

      camera.top = exp_camera_height / 2
      camera.bottom = exp_camera_height / -2
      camera.right = exp_camera_width / 2
      camera.left = exp_camera_width / -2

      camera.near = exp_camera_clip / -2
      camera.far = exp_camera_clip / 2

      camera.updateProjectionMatrix()
      this.viewsRender()
      if (this.sideViews.selectedBox) {
        this.sideViews.update_view_handle(this.sideViews.selectedBox)
      }
    },
    autoSave() {
      if (this.autoSaveParams.add || this.autoSaveParams.edit) {
        return
      }
      this.cubeList.forEach((cubeMesh) => {
        const dbObject = cubeMesh.toDBObject()
        if (!cubeMesh.assets.mMarkAnnotationId) {
          this.autoSaveParams.add = true
          addAnnotation(dbObject).then((res) => {
            this.autoSaveParams.add = false
            if (res.code == '200') {
              cubeMesh.assets.mMarkAnnotationId = res.MarkAnnotationId
              cubeMesh.changed = false
              const readValue = this.markAnnotations.get('MA:' + dbObject.mQaResultId)
              if (readValue) {
                const obj = {
                  mMarkAnnotationId: res.MarkAnnotationId,
                  name: cubeMesh.assets.name,
                  threeD: {
                    bndbox: {
                      x: dbObject.x,
                      y: dbObject.y,
                      z: dbObject.z,
                    },
                    orient_theta: dbObject.orientTheta,
                    other_attributes: {},
                    rotate_theta: dbObject.rotateTheta,
                  },
                }
                for (let ii = 1; ii <= 8; ii++) {
                  obj.threeD.other_attributes['a' + ii] = dbObject['a' + ii]
                  obj.threeD.other_attributes['b' + ii] = dbObject['b' + ii]
                }
                obj.threeD.other_attributes.labels = dbObject.labels
                readValue.object.push(obj)
              }
            }
          })
        } else {
          if (cubeMesh.changed) {
            this.autoSaveParams.edit = true
            editAnnotation(dbObject).then((res) => {
              this.autoSaveParams.edit = false
              if (res.code == '200') {
                cubeMesh.changed = false
                const readValue = this.markAnnotations.get('MA:' + dbObject.mQaResultId)
                if (readValue) {
                  let index = -1
                  for (let ii = 0; ii < readValue.object.length; ii++) {
                    if (readValue.object[ii].mMarkAnnotationId === cubeMesh.assets.mMarkAnnotationId) {
                      index = ii
                      break
                    }
                  }
                  if (index >= 0 && index < readValue.object.length) {
                    const obj = {
                      mMarkAnnotationId: cubeMesh.assets.mMarkAnnotationId,
                      name: cubeMesh.assets.name,
                      threeD: {
                        bndbox: {
                          x: dbObject.x,
                          y: dbObject.y,
                          z: dbObject.z,
                        },
                        orient_theta: dbObject.orientTheta,
                        other_attributes: {},
                        rotate_theta: dbObject.rotateTheta,
                      },
                    }
                    for (let ii = 1; ii <= 8; ii++) {
                      obj.threeD.other_attributes['a' + ii] = dbObject['a' + ii]
                      obj.threeD.other_attributes['b' + ii] = dbObject['b' + ii]
                    }
                    obj.threeD.other_attributes.labels = dbObject.labels
                    readValue.object.splice(index, 1, obj)
                  }
                }
              }
            })
          }
        }
      })
    },
  },
  created() {
    this.selectedObjectA1 = this.$route.query.selectedObjectA1
  },
  mounted() {
    window.addEventListener('resize', this.requestRenderIfNotRequested, false)
  },
  beforeDestroy() {
    this.autoSave()
    cancelAnimationFrame(this.animationFrameId)
    this.camera = null
    if (this.renderer) {
      this.renderer.domElement.removeEventListener('mousemove', this.onMouseMove, false)
      this.renderer.domElement.removeEventListener('mousedown', this.onMouseDown, false)
      this.renderer.domElement.removeEventListener('mouseup', this.onMouseUp, false)
      this.renderer.domElement.removeEventListener('wheel', this.onMouseWheel, false)
      this.renderer.forceContextLoss()
      this.renderer = null
    }
    if (this.labelTool && this.labelTool.onToggleOut) {
      this.labelTool.onToggleOut()
    }
    // window.removeEventListener('resize', this.onWindowResize, false)
    window.addEventListener('resize', this.requestRenderIfNotRequested, false)
  },
}
</script>
<style lang="scss" scoped>
@import './css/main.css';
/* Scale canvas with resize attribute to full size */
canvas[resize] {
  width: 100%;
  height: auto;
}
.point-cloud-container {
  background: #111;
  canvas {
    width: 100%;
    height: 100%;
  }
}
.plan-view-drawer {
  position: absolute;
  right: 0px;
  top: 0px;
  height: 83vh;
  z-index: 1000;
  left: 80%;
  background: #fff;
}
.plane-view-card /deep/ .el-card__header {
  padding: 0 12px;
  line-height: 28px;
  height: 28px;
  min-height: auto;
}
.label {
  text-shadow: -1px 1px 1px rgb(0, 0, 0);
  margin-left: 25px;
  font-size: 20px;
}
/deep/.selectBox {
  border: 1px solid #ffff00;
  background-color: rgba(255, 248, 189, 0.253);
  position: fixed;
}
</style>
